Sat, 03 Jan 2015 20:18:00 +0100
Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "ChangeCSSInlineStyleTxn.h"
7 #include "nsAString.h" // for nsAString_internal::Append, etc
8 #include "nsCRT.h" // for nsCRT
9 #include "nsDebug.h" // for NS_ENSURE_SUCCESS, etc
10 #include "nsError.h" // for NS_ERROR_NULL_POINTER, etc
11 #include "nsGkAtoms.h" // for nsGkAtoms, etc
12 #include "nsIAtom.h" // for nsIAtom
13 #include "nsIDOMCSSStyleDeclaration.h" // for nsIDOMCSSStyleDeclaration
14 #include "nsIDOMElement.h" // for nsIDOMElement
15 #include "nsIDOMElementCSSInlineStyle.h"
16 #include "nsISupportsImpl.h" // for EditTxn::QueryInterface, etc
17 #include "nsISupportsUtils.h" // for NS_ADDREF
18 #include "nsLiteralString.h" // for NS_LITERAL_STRING, etc
19 #include "nsReadableUtils.h" // for ToNewUnicode
20 #include "nsString.h" // for nsAutoString, nsString, etc
21 #include "nsUnicharUtils.h"
22 #include "nsXPCOM.h" // for NS_Free
24 class nsIEditor;
26 #define kNullCh (char16_t('\0'))
28 NS_IMPL_CYCLE_COLLECTION_INHERITED(ChangeCSSInlineStyleTxn, EditTxn,
29 mElement)
31 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ChangeCSSInlineStyleTxn)
32 NS_INTERFACE_MAP_END_INHERITING(EditTxn)
34 // answers true if aValue is in the string list of white-space separated values aValueList
35 // a case-sensitive search is performed if aCaseSensitive is true
36 bool
37 ChangeCSSInlineStyleTxn::ValueIncludes(const nsAString &aValueList, const nsAString &aValue, bool aCaseSensitive)
38 {
39 nsAutoString valueList(aValueList);
40 bool result = false;
42 valueList.Append(kNullCh); // put an extra null at the end
44 char16_t *value = ToNewUnicode(aValue);
45 char16_t *start = valueList.BeginWriting();
46 char16_t *end = start;
48 while (kNullCh != *start) {
49 while ((kNullCh != *start) && nsCRT::IsAsciiSpace(*start)) { // skip leading space
50 start++;
51 }
52 end = start;
54 while ((kNullCh != *end) && (false == nsCRT::IsAsciiSpace(*end))) { // look for space or end
55 end++;
56 }
57 *end = kNullCh; // end string here
59 if (start < end) {
60 if (aCaseSensitive) {
61 if (!nsCRT::strcmp(value, start)) {
62 result = true;
63 break;
64 }
65 }
66 else {
67 if (nsDependentString(value).Equals(nsDependentString(start),
68 nsCaseInsensitiveStringComparator())) {
69 result = true;
70 break;
71 }
72 }
73 }
74 start = ++end;
75 }
76 NS_Free(value);
77 return result;
78 }
80 // removes the value aRemoveValue from the string list of white-space separated values aValueList
81 void
82 ChangeCSSInlineStyleTxn::RemoveValueFromListOfValues(nsAString & aValues, const nsAString & aRemoveValue)
83 {
84 nsAutoString classStr(aValues); // copy to work buffer nsAutoString rv(aRemoveValue);
85 nsAutoString outString;
86 classStr.Append(kNullCh); // put an extra null at the end
88 char16_t *start = classStr.BeginWriting();
89 char16_t *end = start;
91 while (kNullCh != *start) {
92 while ((kNullCh != *start) && nsCRT::IsAsciiSpace(*start)) { // skip leading space
93 start++;
94 }
95 end = start;
97 while ((kNullCh != *end) && (false == nsCRT::IsAsciiSpace(*end))) { // look for space or end
98 end++;
99 }
100 *end = kNullCh; // end string here
102 if (start < end) {
103 if (!aRemoveValue.Equals(start)) {
104 outString.Append(start);
105 outString.Append(char16_t(' '));
106 }
107 }
109 start = ++end;
110 }
111 aValues.Assign(outString);
112 }
114 ChangeCSSInlineStyleTxn::ChangeCSSInlineStyleTxn()
115 : EditTxn()
116 {
117 }
119 NS_IMETHODIMP ChangeCSSInlineStyleTxn::Init(nsIEditor *aEditor,
120 nsIDOMElement *aElement,
121 nsIAtom *aProperty,
122 const nsAString& aValue,
123 bool aRemoveProperty)
124 {
125 NS_ASSERTION(aEditor && aElement, "bad arg");
126 if (!aEditor || !aElement) { return NS_ERROR_NULL_POINTER; }
128 mEditor = aEditor;
129 mElement = do_QueryInterface(aElement);
130 mProperty = aProperty;
131 NS_ADDREF(mProperty);
132 mValue.Assign(aValue);
133 mRemoveProperty = aRemoveProperty;
134 mUndoAttributeWasSet = false;
135 mRedoAttributeWasSet = false;
136 mUndoValue.Truncate();
137 mRedoValue.Truncate();
138 return NS_OK;
139 }
141 NS_IMETHODIMP ChangeCSSInlineStyleTxn::DoTransaction(void)
142 {
143 NS_ASSERTION(mEditor && mElement, "bad state");
144 if (!mEditor || !mElement) { return NS_ERROR_NOT_INITIALIZED; }
146 nsCOMPtr<nsIDOMElementCSSInlineStyle> inlineStyles = do_QueryInterface(mElement);
147 NS_ENSURE_TRUE(inlineStyles, NS_ERROR_NULL_POINTER);
149 nsCOMPtr<nsIDOMCSSStyleDeclaration> cssDecl;
150 nsresult result = inlineStyles->GetStyle(getter_AddRefs(cssDecl));
151 NS_ENSURE_SUCCESS(result, result);
152 NS_ENSURE_TRUE(cssDecl, NS_ERROR_NULL_POINTER);
154 nsAutoString propertyNameString;
155 mProperty->ToString(propertyNameString);
157 NS_NAMED_LITERAL_STRING(styleAttr, "style");
158 result = mElement->HasAttribute(styleAttr, &mUndoAttributeWasSet);
159 NS_ENSURE_SUCCESS(result, result);
161 nsAutoString values;
162 result = cssDecl->GetPropertyValue(propertyNameString, values);
163 NS_ENSURE_SUCCESS(result, result);
164 mUndoValue.Assign(values);
166 // does this property accept more than 1 value ?
167 // we need to know that because of bug 62682
168 bool multiple = AcceptsMoreThanOneValue(mProperty);
170 if (mRemoveProperty) {
171 nsAutoString returnString;
172 if (multiple) {
173 // the property can have more than one value, let's remove only
174 // the value we have to remove and not the others
176 // the 2 lines below are a workaround because nsDOMCSSDeclaration::GetPropertyCSSValue
177 // is not yet implemented (bug 62682)
178 RemoveValueFromListOfValues(values, NS_LITERAL_STRING("none"));
179 RemoveValueFromListOfValues(values, mValue);
180 if (values.IsEmpty()) {
181 result = cssDecl->RemoveProperty(propertyNameString, returnString);
182 NS_ENSURE_SUCCESS(result, result);
183 }
184 else {
185 nsAutoString priority;
186 result = cssDecl->GetPropertyPriority(propertyNameString, priority);
187 NS_ENSURE_SUCCESS(result, result);
188 result = cssDecl->SetProperty(propertyNameString, values,
189 priority);
190 NS_ENSURE_SUCCESS(result, result);
191 }
192 }
193 else {
194 result = cssDecl->RemoveProperty(propertyNameString, returnString);
195 NS_ENSURE_SUCCESS(result, result);
196 }
197 }
198 else {
199 nsAutoString priority;
200 result = cssDecl->GetPropertyPriority(propertyNameString, priority);
201 NS_ENSURE_SUCCESS(result, result);
202 if (multiple) {
203 // the property can have more than one value, let's add
204 // the value we have to add to the others
206 // the line below is a workaround because nsDOMCSSDeclaration::GetPropertyCSSValue
207 // is not yet implemented (bug 62682)
208 AddValueToMultivalueProperty(values, mValue);
209 }
210 else
211 values.Assign(mValue);
212 result = cssDecl->SetProperty(propertyNameString, values,
213 priority);
214 NS_ENSURE_SUCCESS(result, result);
215 }
217 // let's be sure we don't keep an empty style attribute
218 uint32_t length;
219 result = cssDecl->GetLength(&length);
220 NS_ENSURE_SUCCESS(result, result);
221 if (!length) {
222 result = mElement->RemoveAttribute(styleAttr);
223 NS_ENSURE_SUCCESS(result, result);
224 }
225 else
226 mRedoAttributeWasSet = true;
228 return cssDecl->GetPropertyValue(propertyNameString, mRedoValue);
229 }
231 nsresult ChangeCSSInlineStyleTxn::SetStyle(bool aAttributeWasSet,
232 nsAString & aValue)
233 {
234 NS_ASSERTION(mEditor && mElement, "bad state");
235 if (!mEditor || !mElement) { return NS_ERROR_NOT_INITIALIZED; }
237 nsresult result = NS_OK;
238 if (aAttributeWasSet) {
239 // the style attribute was set and not empty, let's recreate the declaration
240 nsAutoString propertyNameString;
241 mProperty->ToString(propertyNameString);
243 nsCOMPtr<nsIDOMElementCSSInlineStyle> inlineStyles = do_QueryInterface(mElement);
244 NS_ENSURE_TRUE(inlineStyles, NS_ERROR_NULL_POINTER);
245 nsCOMPtr<nsIDOMCSSStyleDeclaration> cssDecl;
246 result = inlineStyles->GetStyle(getter_AddRefs(cssDecl));
247 NS_ENSURE_SUCCESS(result, result);
248 NS_ENSURE_TRUE(cssDecl, NS_ERROR_NULL_POINTER);
250 if (aValue.IsEmpty()) {
251 // an empty value means we have to remove the property
252 nsAutoString returnString;
253 result = cssDecl->RemoveProperty(propertyNameString, returnString);
254 }
255 else {
256 // let's recreate the declaration as it was
257 nsAutoString priority;
258 result = cssDecl->GetPropertyPriority(propertyNameString, priority);
259 NS_ENSURE_SUCCESS(result, result);
260 result = cssDecl->SetProperty(propertyNameString, aValue, priority);
261 }
262 }
263 else
264 result = mElement->RemoveAttribute(NS_LITERAL_STRING("style"));
266 return result;
267 }
269 NS_IMETHODIMP ChangeCSSInlineStyleTxn::UndoTransaction(void)
270 {
271 return SetStyle(mUndoAttributeWasSet, mUndoValue);
272 }
274 NS_IMETHODIMP ChangeCSSInlineStyleTxn::RedoTransaction(void)
275 {
276 return SetStyle(mRedoAttributeWasSet, mRedoValue);
277 }
279 NS_IMETHODIMP ChangeCSSInlineStyleTxn::GetTxnDescription(nsAString& aString)
280 {
281 aString.AssignLiteral("ChangeCSSInlineStyleTxn: [mRemoveProperty == ");
283 if (!mRemoveProperty)
284 aString.AppendLiteral("false] ");
285 else
286 aString.AppendLiteral("true] ");
287 nsAutoString tempString;
288 mProperty->ToString(tempString);
289 aString += tempString;
290 return NS_OK;
291 }
293 // answers true if the CSS property accepts more than one value
294 bool
295 ChangeCSSInlineStyleTxn::AcceptsMoreThanOneValue(nsIAtom *aCSSProperty)
296 {
297 return aCSSProperty == nsGkAtoms::text_decoration;
298 }
300 // adds the value aNewValue to the list of white-space separated values aValues
301 NS_IMETHODIMP
302 ChangeCSSInlineStyleTxn::AddValueToMultivalueProperty(nsAString & aValues, const nsAString & aNewValue)
303 {
304 if (aValues.IsEmpty()
305 || aValues.LowerCaseEqualsLiteral("none")) {
306 // the list of values is empty of the value is 'none'
307 aValues.Assign(aNewValue);
308 }
309 else if (!ValueIncludes(aValues, aNewValue, false)) {
310 // we already have another value but not this one; add it
311 aValues.Append(char16_t(' '));
312 aValues.Append(aNewValue);
313 }
314 return NS_OK;
315 }