Bug 473680. Stop crashtest 458637-1.html early (returning success) if it's running...
[mozilla-central.git] / layout / style / nsCSSValue.cpp
blob44e0ec1550c90f88966bd6cec16d5381039392d0
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
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/
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.
15 * The Original Code is mozilla.org code.
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.
22 * Contributor(s):
24 * Alternatively, the contents of this file may be used under the terms of
25 * either of the GNU General Public License Version 2 or later (the "GPL"),
26 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 * in which case the provisions of the GPL or the LGPL are applicable instead
28 * of those above. If you wish to allow use of your version of this file only
29 * under the terms of either the GPL or the LGPL, and not to allow others to
30 * use your version of this file under the terms of the MPL, indicate your
31 * decision by deleting the provisions above and replace them with the notice
32 * and other provisions required by the GPL or the LGPL. If you do not delete
33 * the provisions above, a recipient may use your version of this file under
34 * the terms of any one of the MPL, the GPL or the LGPL.
36 * ***** END LICENSE BLOCK ***** */
38 /* representation of simple property values within CSS declarations */
40 #include "nsCSSValue.h"
41 #include "nsString.h"
42 #include "nsCSSProps.h"
43 #include "nsReadableUtils.h"
44 #include "imgIRequest.h"
45 #include "nsIDocument.h"
46 #include "nsContentUtils.h"
47 #include "nsIPrincipal.h"
49 // Paint forcing
50 #include "prenv.h"
52 nsCSSValue::nsCSSValue(PRInt32 aValue, nsCSSUnit aUnit)
53 : mUnit(aUnit)
55 NS_ASSERTION(aUnit == eCSSUnit_Integer || aUnit == eCSSUnit_Enumerated ||
56 aUnit == eCSSUnit_EnumColor, "not an int value");
57 if (aUnit == eCSSUnit_Integer || aUnit == eCSSUnit_Enumerated ||
58 aUnit == eCSSUnit_EnumColor) {
59 mValue.mInt = aValue;
61 else {
62 mUnit = eCSSUnit_Null;
63 mValue.mInt = 0;
67 nsCSSValue::nsCSSValue(float aValue, nsCSSUnit aUnit)
68 : mUnit(aUnit)
70 NS_ASSERTION(eCSSUnit_Percent <= aUnit, "not a float value");
71 if (eCSSUnit_Percent <= aUnit) {
72 mValue.mFloat = aValue;
74 else {
75 mUnit = eCSSUnit_Null;
76 mValue.mInt = 0;
80 nsCSSValue::nsCSSValue(const nsString& aValue, nsCSSUnit aUnit)
81 : mUnit(aUnit)
83 NS_ASSERTION(UnitHasStringValue(), "not a string value");
84 if (UnitHasStringValue()) {
85 mValue.mString = BufferFromString(aValue);
86 if (NS_UNLIKELY(!mValue.mString)) {
87 // XXXbz not much we can do here; just make sure that our promise of a
88 // non-null mValue.mString holds for string units.
89 mUnit = eCSSUnit_Null;
92 else {
93 mUnit = eCSSUnit_Null;
94 mValue.mInt = 0;
98 nsCSSValue::nsCSSValue(nscolor aValue)
99 : mUnit(eCSSUnit_Color)
101 mValue.mColor = aValue;
104 nsCSSValue::nsCSSValue(nsCSSValue::Array* aValue, nsCSSUnit aUnit)
105 : mUnit(aUnit)
107 NS_ASSERTION(eCSSUnit_Array <= aUnit && aUnit <= eCSSUnit_Function,
108 "bad unit");
109 mValue.mArray = aValue;
110 mValue.mArray->AddRef();
113 nsCSSValue::nsCSSValue(nsCSSValue::URL* aValue)
114 : mUnit(eCSSUnit_URL)
116 mValue.mURL = aValue;
117 mValue.mURL->AddRef();
120 nsCSSValue::nsCSSValue(nsCSSValue::Image* aValue)
121 : mUnit(eCSSUnit_Image)
123 mValue.mImage = aValue;
124 mValue.mImage->AddRef();
127 nsCSSValue::nsCSSValue(const nsCSSValue& aCopy)
128 : mUnit(aCopy.mUnit)
130 if (mUnit <= eCSSUnit_RectIsAuto) {
131 // nothing to do, but put this important case first
133 else if (eCSSUnit_Percent <= mUnit) {
134 mValue.mFloat = aCopy.mValue.mFloat;
136 else if (UnitHasStringValue()) {
137 mValue.mString = aCopy.mValue.mString;
138 mValue.mString->AddRef();
140 else if (eCSSUnit_Integer <= mUnit && mUnit <= eCSSUnit_EnumColor) {
141 mValue.mInt = aCopy.mValue.mInt;
143 else if (eCSSUnit_Color == mUnit) {
144 mValue.mColor = aCopy.mValue.mColor;
146 else if (eCSSUnit_Array <= mUnit && mUnit <= eCSSUnit_Function) {
147 mValue.mArray = aCopy.mValue.mArray;
148 mValue.mArray->AddRef();
150 else if (eCSSUnit_URL == mUnit) {
151 mValue.mURL = aCopy.mValue.mURL;
152 mValue.mURL->AddRef();
154 else if (eCSSUnit_Image == mUnit) {
155 mValue.mImage = aCopy.mValue.mImage;
156 mValue.mImage->AddRef();
158 else {
159 NS_NOTREACHED("unknown unit");
163 nsCSSValue& nsCSSValue::operator=(const nsCSSValue& aCopy)
165 if (this != &aCopy) {
166 Reset();
167 new (this) nsCSSValue(aCopy);
169 return *this;
172 PRBool nsCSSValue::operator==(const nsCSSValue& aOther) const
174 if (mUnit == aOther.mUnit) {
175 if (mUnit <= eCSSUnit_RectIsAuto) {
176 return PR_TRUE;
178 else if (UnitHasStringValue()) {
179 return (NS_strcmp(GetBufferValue(mValue.mString),
180 GetBufferValue(aOther.mValue.mString)) == 0);
182 else if ((eCSSUnit_Integer <= mUnit) && (mUnit <= eCSSUnit_EnumColor)) {
183 return mValue.mInt == aOther.mValue.mInt;
185 else if (eCSSUnit_Color == mUnit) {
186 return mValue.mColor == aOther.mValue.mColor;
188 else if (eCSSUnit_Array <= mUnit && mUnit <= eCSSUnit_Function) {
189 return *mValue.mArray == *aOther.mValue.mArray;
191 else if (eCSSUnit_URL == mUnit) {
192 return *mValue.mURL == *aOther.mValue.mURL;
194 else if (eCSSUnit_Image == mUnit) {
195 return *mValue.mImage == *aOther.mValue.mImage;
197 else {
198 return mValue.mFloat == aOther.mValue.mFloat;
201 return PR_FALSE;
204 imgIRequest* nsCSSValue::GetImageValue() const
206 NS_ASSERTION(mUnit == eCSSUnit_Image, "not an Image value");
207 return mValue.mImage->mRequest;
210 nscoord nsCSSValue::GetLengthTwips() const
212 NS_ASSERTION(IsFixedLengthUnit(), "not a fixed length unit");
214 if (IsFixedLengthUnit()) {
215 switch (mUnit) {
216 case eCSSUnit_Inch:
217 return NS_INCHES_TO_TWIPS(mValue.mFloat);
218 case eCSSUnit_Foot:
219 return NS_FEET_TO_TWIPS(mValue.mFloat);
220 case eCSSUnit_Mile:
221 return NS_MILES_TO_TWIPS(mValue.mFloat);
223 case eCSSUnit_Millimeter:
224 return NS_MILLIMETERS_TO_TWIPS(mValue.mFloat);
225 case eCSSUnit_Centimeter:
226 return NS_CENTIMETERS_TO_TWIPS(mValue.mFloat);
227 case eCSSUnit_Meter:
228 return NS_METERS_TO_TWIPS(mValue.mFloat);
229 case eCSSUnit_Kilometer:
230 return NS_KILOMETERS_TO_TWIPS(mValue.mFloat);
232 case eCSSUnit_Point:
233 return NS_POINTS_TO_TWIPS(mValue.mFloat);
234 case eCSSUnit_Pica:
235 return NS_PICAS_TO_TWIPS(mValue.mFloat);
236 case eCSSUnit_Didot:
237 return NS_DIDOTS_TO_TWIPS(mValue.mFloat);
238 case eCSSUnit_Cicero:
239 return NS_CICEROS_TO_TWIPS(mValue.mFloat);
240 default:
241 NS_ERROR("should never get here");
242 break;
245 return 0;
248 void nsCSSValue::DoReset()
250 if (UnitHasStringValue()) {
251 mValue.mString->Release();
252 } else if (eCSSUnit_Array <= mUnit && mUnit <= eCSSUnit_Function) {
253 mValue.mArray->Release();
254 } else if (eCSSUnit_URL == mUnit) {
255 mValue.mURL->Release();
256 } else if (eCSSUnit_Image == mUnit) {
257 mValue.mImage->Release();
259 mUnit = eCSSUnit_Null;
262 void nsCSSValue::SetIntValue(PRInt32 aValue, nsCSSUnit aUnit)
264 NS_ASSERTION(aUnit == eCSSUnit_Integer || aUnit == eCSSUnit_Enumerated ||
265 aUnit == eCSSUnit_EnumColor, "not an int value");
266 Reset();
267 if (aUnit == eCSSUnit_Integer || aUnit == eCSSUnit_Enumerated ||
268 aUnit == eCSSUnit_EnumColor) {
269 mUnit = aUnit;
270 mValue.mInt = aValue;
274 void nsCSSValue::SetPercentValue(float aValue)
276 Reset();
277 mUnit = eCSSUnit_Percent;
278 mValue.mFloat = aValue;
281 void nsCSSValue::SetFloatValue(float aValue, nsCSSUnit aUnit)
283 NS_ASSERTION(eCSSUnit_Number <= aUnit, "not a float value");
284 Reset();
285 if (eCSSUnit_Number <= aUnit) {
286 mUnit = aUnit;
287 mValue.mFloat = aValue;
291 void nsCSSValue::SetStringValue(const nsString& aValue,
292 nsCSSUnit aUnit)
294 Reset();
295 mUnit = aUnit;
296 NS_ASSERTION(UnitHasStringValue(), "not a string unit");
297 if (UnitHasStringValue()) {
298 mValue.mString = BufferFromString(aValue);
299 if (NS_UNLIKELY(!mValue.mString)) {
300 // XXXbz not much we can do here; just make sure that our promise of a
301 // non-null mValue.mString holds for string units.
302 mUnit = eCSSUnit_Null;
304 } else
305 mUnit = eCSSUnit_Null;
308 void nsCSSValue::SetColorValue(nscolor aValue)
310 Reset();
311 mUnit = eCSSUnit_Color;
312 mValue.mColor = aValue;
315 void nsCSSValue::SetArrayValue(nsCSSValue::Array* aValue, nsCSSUnit aUnit)
317 NS_ASSERTION(eCSSUnit_Array <= aUnit && aUnit <= eCSSUnit_Function,
318 "bad unit");
319 Reset();
320 mUnit = aUnit;
321 mValue.mArray = aValue;
322 mValue.mArray->AddRef();
325 void nsCSSValue::SetURLValue(nsCSSValue::URL* aValue)
327 Reset();
328 mUnit = eCSSUnit_URL;
329 mValue.mURL = aValue;
330 mValue.mURL->AddRef();
333 void nsCSSValue::SetImageValue(nsCSSValue::Image* aValue)
335 Reset();
336 mUnit = eCSSUnit_Image;
337 mValue.mImage = aValue;
338 mValue.mImage->AddRef();
341 void nsCSSValue::SetAutoValue()
343 Reset();
344 mUnit = eCSSUnit_Auto;
347 void nsCSSValue::SetInheritValue()
349 Reset();
350 mUnit = eCSSUnit_Inherit;
353 void nsCSSValue::SetInitialValue()
355 Reset();
356 mUnit = eCSSUnit_Initial;
359 void nsCSSValue::SetNoneValue()
361 Reset();
362 mUnit = eCSSUnit_None;
365 void nsCSSValue::SetNormalValue()
367 Reset();
368 mUnit = eCSSUnit_Normal;
371 void nsCSSValue::SetSystemFontValue()
373 Reset();
374 mUnit = eCSSUnit_System_Font;
377 void nsCSSValue::SetDummyValue()
379 Reset();
380 mUnit = eCSSUnit_Dummy;
383 void nsCSSValue::SetDummyInheritValue()
385 Reset();
386 mUnit = eCSSUnit_DummyInherit;
389 void nsCSSValue::SetRectIsAutoValue()
391 Reset();
392 mUnit = eCSSUnit_RectIsAuto;
395 void nsCSSValue::StartImageLoad(nsIDocument* aDocument) const
397 NS_PRECONDITION(eCSSUnit_URL == mUnit, "Not a URL value!");
398 nsCSSValue::Image* image =
399 new nsCSSValue::Image(mValue.mURL->mURI,
400 mValue.mURL->mString,
401 mValue.mURL->mReferrer,
402 mValue.mURL->mOriginPrincipal,
403 aDocument);
404 if (image) {
405 nsCSSValue* writable = const_cast<nsCSSValue*>(this);
406 writable->SetImageValue(image);
410 // static
411 nsStringBuffer*
412 nsCSSValue::BufferFromString(const nsString& aValue)
414 nsStringBuffer* buffer = nsStringBuffer::FromString(aValue);
415 if (buffer) {
416 buffer->AddRef();
417 return buffer;
420 PRUnichar length = aValue.Length();
421 buffer = nsStringBuffer::Alloc((length + 1) * sizeof(PRUnichar));
422 if (NS_LIKELY(buffer != 0)) {
423 PRUnichar* data = static_cast<PRUnichar*>(buffer->Data());
424 nsCharTraits<PRUnichar>::copy(data, aValue.get(), length);
425 // Null-terminate.
426 data[length] = 0;
429 return buffer;
432 nsCSSValue::URL::URL(nsIURI* aURI, nsStringBuffer* aString, nsIURI* aReferrer,
433 nsIPrincipal* aOriginPrincipal)
434 : mURI(aURI),
435 mString(aString),
436 mReferrer(aReferrer),
437 mOriginPrincipal(aOriginPrincipal),
438 mRefCnt(0)
440 NS_PRECONDITION(aOriginPrincipal, "Must have an origin principal");
442 mString->AddRef();
443 MOZ_COUNT_CTOR(nsCSSValue::URL);
446 nsCSSValue::URL::~URL()
448 mString->Release();
449 MOZ_COUNT_DTOR(nsCSSValue::URL);
452 PRBool
453 nsCSSValue::URL::operator==(const URL& aOther) const
455 PRBool eq;
456 return NS_strcmp(GetBufferValue(mString),
457 GetBufferValue(aOther.mString)) == 0 &&
458 (mURI == aOther.mURI || // handles null == null
459 (mURI && aOther.mURI &&
460 NS_SUCCEEDED(mURI->Equals(aOther.mURI, &eq)) &&
461 eq)) &&
462 (mOriginPrincipal == aOther.mOriginPrincipal ||
463 (NS_SUCCEEDED(mOriginPrincipal->Equals(aOther.mOriginPrincipal,
464 &eq)) && eq));
467 PRBool
468 nsCSSValue::URL::URIEquals(const URL& aOther) const
470 PRBool eq;
471 // Worth comparing mURI to aOther.mURI and mOriginPrincipal to
472 // aOther.mOriginPrincipal, because in the (probably common) case when this
473 // value was one of the ones that in fact did not change this will be our
474 // fast path to equality
475 return (mURI == aOther.mURI ||
476 (NS_SUCCEEDED(mURI->Equals(aOther.mURI, &eq)) && eq)) &&
477 (mOriginPrincipal == aOther.mOriginPrincipal ||
478 (NS_SUCCEEDED(mOriginPrincipal->Equals(aOther.mOriginPrincipal,
479 &eq)) && eq));
482 nsCSSValue::Image::Image(nsIURI* aURI, nsStringBuffer* aString,
483 nsIURI* aReferrer, nsIPrincipal* aOriginPrincipal,
484 nsIDocument* aDocument)
485 : URL(aURI, aString, aReferrer, aOriginPrincipal)
487 MOZ_COUNT_CTOR(nsCSSValue::Image);
489 if (mURI &&
490 nsContentUtils::CanLoadImage(mURI, aDocument, aDocument,
491 aOriginPrincipal)) {
492 nsContentUtils::LoadImage(mURI, aDocument, aOriginPrincipal, aReferrer,
493 nsnull, nsIRequest::LOAD_NORMAL,
494 getter_AddRefs(mRequest));
498 nsCSSValue::Image::~Image()
500 MOZ_COUNT_DTOR(nsCSSValue::Image);