1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is Mozilla Communicator client code.
16 : *
17 : * The Initial Developer of the Original Code is
18 : * Netscape Communications Corporation.
19 : * Portions created by the Initial Developer are Copyright (C) 1998
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : * David Hyatt <hyatt@netscape.com> (Original Author)
24 : *
25 : * Alternatively, the contents of this file may be used under the terms of
26 : * either of the GNU General Public License Version 2 or later (the "GPL"),
27 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 : * in which case the provisions of the GPL or the LGPL are applicable instead
29 : * of those above. If you wish to allow use of your version of this file only
30 : * under the terms of either the GPL or the LGPL, and not to allow others to
31 : * use your version of this file under the terms of the MPL, indicate your
32 : * decision by deleting the provisions above and replace them with the notice
33 : * and other provisions required by the GPL or the LGPL. If you do not delete
34 : * the provisions above, a recipient may use your version of this file under
35 : * the terms of any one of the MPL, the GPL or the LGPL.
36 : *
37 : * ***** END LICENSE BLOCK ***** */
38 :
39 : #include "nsIAtom.h"
40 : #include "nsString.h"
41 : #include "jsapi.h"
42 : #include "nsIContent.h"
43 : #include "nsString.h"
44 : #include "nsUnicharUtils.h"
45 : #include "nsReadableUtils.h"
46 : #include "mozilla/FunctionTimer.h"
47 : #include "nsXBLProtoImplField.h"
48 : #include "nsIScriptContext.h"
49 : #include "nsContentUtils.h"
50 : #include "nsIURI.h"
51 : #include "nsXBLSerialize.h"
52 : #include "nsXBLPrototypeBinding.h"
53 :
54 0 : nsXBLProtoImplField::nsXBLProtoImplField(const PRUnichar* aName, const PRUnichar* aReadOnly)
55 : : mNext(nsnull),
56 : mFieldText(nsnull),
57 : mFieldTextLength(0),
58 0 : mLineNumber(0)
59 : {
60 0 : MOZ_COUNT_CTOR(nsXBLProtoImplField);
61 0 : mName = NS_strdup(aName); // XXXbz make more sense to use a stringbuffer?
62 :
63 0 : mJSAttributes = JSPROP_ENUMERATE;
64 0 : if (aReadOnly) {
65 0 : nsAutoString readOnly; readOnly.Assign(aReadOnly);
66 0 : if (readOnly.LowerCaseEqualsLiteral("true"))
67 0 : mJSAttributes |= JSPROP_READONLY;
68 : }
69 0 : }
70 :
71 :
72 0 : nsXBLProtoImplField::nsXBLProtoImplField(const bool aIsReadOnly)
73 : : mNext(nsnull),
74 : mFieldText(nsnull),
75 : mFieldTextLength(0),
76 0 : mLineNumber(0)
77 : {
78 0 : MOZ_COUNT_CTOR(nsXBLProtoImplField);
79 :
80 0 : mJSAttributes = JSPROP_ENUMERATE;
81 0 : if (aIsReadOnly)
82 0 : mJSAttributes |= JSPROP_READONLY;
83 0 : }
84 :
85 0 : nsXBLProtoImplField::~nsXBLProtoImplField()
86 : {
87 0 : MOZ_COUNT_DTOR(nsXBLProtoImplField);
88 0 : if (mFieldText)
89 0 : nsMemory::Free(mFieldText);
90 0 : NS_Free(mName);
91 0 : NS_CONTENT_DELETE_LIST_MEMBER(nsXBLProtoImplField, this, mNext);
92 0 : }
93 :
94 : void
95 0 : nsXBLProtoImplField::AppendFieldText(const nsAString& aText)
96 : {
97 0 : if (mFieldText) {
98 0 : nsDependentString fieldTextStr(mFieldText, mFieldTextLength);
99 0 : nsAutoString newFieldText = fieldTextStr + aText;
100 0 : PRUnichar* temp = mFieldText;
101 0 : mFieldText = ToNewUnicode(newFieldText);
102 0 : mFieldTextLength = newFieldText.Length();
103 0 : nsMemory::Free(temp);
104 : }
105 : else {
106 0 : mFieldText = ToNewUnicode(aText);
107 0 : mFieldTextLength = aText.Length();
108 : }
109 0 : }
110 :
111 : nsresult
112 0 : nsXBLProtoImplField::InstallField(nsIScriptContext* aContext,
113 : JSObject* aBoundNode,
114 : nsIPrincipal* aPrincipal,
115 : nsIURI* aBindingDocURI,
116 : bool* aDidInstall) const
117 : {
118 : NS_TIME_FUNCTION_MIN(5);
119 0 : NS_PRECONDITION(aBoundNode,
120 : "uh-oh, bound node should NOT be null or bad things will "
121 : "happen");
122 :
123 0 : *aDidInstall = false;
124 :
125 0 : if (mFieldTextLength == 0) {
126 0 : return NS_OK;
127 : }
128 :
129 : // EvaluateStringWithValue and JS_DefineUCProperty can both trigger GC, so
130 : // protect |result| here.
131 : nsresult rv;
132 :
133 0 : nsCAutoString uriSpec;
134 0 : aBindingDocURI->GetSpec(uriSpec);
135 :
136 0 : JSContext* cx = aContext->GetNativeContext();
137 0 : NS_ASSERTION(!::JS_IsExceptionPending(cx),
138 : "Shouldn't get here when an exception is pending!");
139 :
140 : // compile the literal string
141 : bool undefined;
142 0 : nsCOMPtr<nsIScriptContext> context = aContext;
143 :
144 0 : JSAutoRequest ar(cx);
145 0 : jsval result = JSVAL_NULL;
146 0 : rv = context->EvaluateStringWithValue(nsDependentString(mFieldText,
147 0 : mFieldTextLength),
148 : aBoundNode,
149 : aPrincipal, uriSpec.get(),
150 : mLineNumber, JSVERSION_LATEST,
151 0 : &result, &undefined);
152 0 : if (NS_FAILED(rv)) {
153 0 : return rv;
154 : }
155 :
156 0 : if (undefined) {
157 0 : result = JSVAL_VOID;
158 : }
159 :
160 : // Define the evaluated result as a JS property
161 0 : nsDependentString name(mName);
162 0 : if (!::JS_DefineUCProperty(cx, aBoundNode,
163 : reinterpret_cast<const jschar*>(mName),
164 : name.Length(), result, nsnull, nsnull,
165 0 : mJSAttributes)) {
166 0 : return NS_ERROR_OUT_OF_MEMORY;
167 : }
168 :
169 0 : *aDidInstall = true;
170 0 : return NS_OK;
171 : }
172 :
173 : nsresult
174 0 : nsXBLProtoImplField::Read(nsIScriptContext* aContext,
175 : nsIObjectInputStream* aStream)
176 : {
177 0 : nsAutoString name;
178 0 : nsresult rv = aStream->ReadString(name);
179 0 : NS_ENSURE_SUCCESS(rv, rv);
180 0 : mName = ToNewUnicode(name);
181 :
182 0 : rv = aStream->Read32(&mLineNumber);
183 0 : NS_ENSURE_SUCCESS(rv, rv);
184 :
185 0 : nsAutoString fieldText;
186 0 : rv = aStream->ReadString(fieldText);
187 0 : NS_ENSURE_SUCCESS(rv, rv);
188 0 : mFieldTextLength = fieldText.Length();
189 0 : if (mFieldTextLength)
190 0 : mFieldText = ToNewUnicode(fieldText);
191 :
192 0 : return NS_OK;
193 : }
194 :
195 : nsresult
196 0 : nsXBLProtoImplField::Write(nsIScriptContext* aContext,
197 : nsIObjectOutputStream* aStream)
198 : {
199 0 : XBLBindingSerializeDetails type = XBLBinding_Serialize_Field;
200 :
201 0 : if (mJSAttributes & JSPROP_READONLY) {
202 0 : type |= XBLBinding_Serialize_ReadOnly;
203 : }
204 :
205 0 : nsresult rv = aStream->Write8(type);
206 0 : NS_ENSURE_SUCCESS(rv, rv);
207 0 : rv = aStream->WriteWStringZ(mName);
208 0 : NS_ENSURE_SUCCESS(rv, rv);
209 0 : rv = aStream->Write32(mLineNumber);
210 0 : NS_ENSURE_SUCCESS(rv, rv);
211 :
212 0 : return aStream->WriteWStringZ(mFieldText ? mFieldText : EmptyString().get());
213 : }
|