Line data Source code
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/. */
5 :
6 : /*
7 : * representation of media lists used when linking to style sheets or by
8 : * @media rules
9 : */
10 :
11 : #include "nsMediaList.h"
12 :
13 : #include "nsCSSParser.h"
14 : #include "nsCSSRules.h"
15 : #include "nsMediaFeatures.h"
16 : #include "nsRuleNode.h"
17 :
18 : using namespace mozilla;
19 :
20 : template <class Numeric>
21 238 : int32_t DoCompare(Numeric a, Numeric b)
22 : {
23 238 : if (a == b)
24 86 : return 0;
25 152 : if (a < b)
26 33 : return -1;
27 119 : return 1;
28 : }
29 :
30 : bool
31 375 : nsMediaExpression::Matches(nsPresContext *aPresContext,
32 : const nsCSSValue& aActualValue) const
33 : {
34 375 : const nsCSSValue& actual = aActualValue;
35 375 : const nsCSSValue& required = mValue;
36 :
37 : // If we don't have the feature, the match fails.
38 375 : if (actual.GetUnit() == eCSSUnit_Null) {
39 1 : return false;
40 : }
41 :
42 : // If the expression had no value to match, the match succeeds,
43 : // unless the value is an integer 0 or a zero length.
44 374 : if (required.GetUnit() == eCSSUnit_Null) {
45 136 : if (actual.GetUnit() == eCSSUnit_Integer)
46 136 : return actual.GetIntValue() != 0;
47 0 : if (actual.IsLengthUnit())
48 0 : return actual.GetFloatValue() != 0;
49 0 : return true;
50 : }
51 :
52 238 : NS_ASSERTION(mFeature->mRangeType == nsMediaFeature::eMinMaxAllowed ||
53 : mRange == nsMediaExpression::eEqual, "yikes");
54 : int32_t cmp; // -1 (actual < required)
55 : // 0 (actual == required)
56 : // 1 (actual > required)
57 238 : switch (mFeature->mValueType) {
58 : case nsMediaFeature::eLength:
59 : {
60 31 : NS_ASSERTION(actual.IsLengthUnit(), "bad actual value");
61 31 : NS_ASSERTION(required.IsLengthUnit(), "bad required value");
62 : nscoord actualCoord = nsRuleNode::CalcLengthWithInitialFont(
63 31 : aPresContext, actual);
64 : nscoord requiredCoord = nsRuleNode::CalcLengthWithInitialFont(
65 31 : aPresContext, required);
66 31 : cmp = DoCompare(actualCoord, requiredCoord);
67 : }
68 31 : break;
69 : case nsMediaFeature::eInteger:
70 : case nsMediaFeature::eBoolInteger:
71 : {
72 0 : NS_ASSERTION(actual.GetUnit() == eCSSUnit_Integer,
73 : "bad actual value");
74 0 : NS_ASSERTION(required.GetUnit() == eCSSUnit_Integer,
75 : "bad required value");
76 0 : NS_ASSERTION(mFeature->mValueType != nsMediaFeature::eBoolInteger ||
77 : actual.GetIntValue() == 0 || actual.GetIntValue() == 1,
78 : "bad actual bool integer value");
79 0 : NS_ASSERTION(mFeature->mValueType != nsMediaFeature::eBoolInteger ||
80 : required.GetIntValue() == 0 || required.GetIntValue() == 1,
81 : "bad required bool integer value");
82 0 : cmp = DoCompare(actual.GetIntValue(), required.GetIntValue());
83 : }
84 0 : break;
85 : case nsMediaFeature::eFloat:
86 : {
87 0 : NS_ASSERTION(actual.GetUnit() == eCSSUnit_Number,
88 : "bad actual value");
89 0 : NS_ASSERTION(required.GetUnit() == eCSSUnit_Number,
90 : "bad required value");
91 0 : cmp = DoCompare(actual.GetFloatValue(), required.GetFloatValue());
92 : }
93 0 : break;
94 : case nsMediaFeature::eIntRatio:
95 : {
96 0 : NS_ASSERTION(actual.GetUnit() == eCSSUnit_Array &&
97 : actual.GetArrayValue()->Count() == 2 &&
98 : actual.GetArrayValue()->Item(0).GetUnit() ==
99 : eCSSUnit_Integer &&
100 : actual.GetArrayValue()->Item(1).GetUnit() ==
101 : eCSSUnit_Integer,
102 : "bad actual value");
103 0 : NS_ASSERTION(required.GetUnit() == eCSSUnit_Array &&
104 : required.GetArrayValue()->Count() == 2 &&
105 : required.GetArrayValue()->Item(0).GetUnit() ==
106 : eCSSUnit_Integer &&
107 : required.GetArrayValue()->Item(1).GetUnit() ==
108 : eCSSUnit_Integer,
109 : "bad required value");
110 : // Convert to int64_t so we can multiply without worry. Note
111 : // that while the spec requires that both halves of |required|
112 : // be positive, the numerator or denominator of |actual| might
113 : // be zero (e.g., when testing 'aspect-ratio' on a 0-width or
114 : // 0-height iframe).
115 0 : int64_t actualNum = actual.GetArrayValue()->Item(0).GetIntValue(),
116 0 : actualDen = actual.GetArrayValue()->Item(1).GetIntValue(),
117 0 : requiredNum = required.GetArrayValue()->Item(0).GetIntValue(),
118 0 : requiredDen = required.GetArrayValue()->Item(1).GetIntValue();
119 0 : cmp = DoCompare(actualNum * requiredDen, requiredNum * actualDen);
120 : }
121 0 : break;
122 : case nsMediaFeature::eResolution:
123 : {
124 207 : NS_ASSERTION(actual.GetUnit() == eCSSUnit_Inch ||
125 : actual.GetUnit() == eCSSUnit_Pixel ||
126 : actual.GetUnit() == eCSSUnit_Centimeter,
127 : "bad actual value");
128 207 : NS_ASSERTION(required.GetUnit() == eCSSUnit_Inch ||
129 : required.GetUnit() == eCSSUnit_Pixel ||
130 : required.GetUnit() == eCSSUnit_Centimeter,
131 : "bad required value");
132 207 : float actualDPI = actual.GetFloatValue();
133 207 : float overrideDPPX = aPresContext->GetOverrideDPPX();
134 :
135 207 : if (overrideDPPX > 0) {
136 0 : actualDPI = overrideDPPX * 96.0f;
137 207 : } else if (actual.GetUnit() == eCSSUnit_Centimeter) {
138 0 : actualDPI = actualDPI * 2.54f;
139 207 : } else if (actual.GetUnit() == eCSSUnit_Pixel) {
140 0 : actualDPI = actualDPI * 96.0f;
141 : }
142 207 : float requiredDPI = required.GetFloatValue();
143 207 : if (required.GetUnit() == eCSSUnit_Centimeter) {
144 0 : requiredDPI = requiredDPI * 2.54f;
145 207 : } else if (required.GetUnit() == eCSSUnit_Pixel) {
146 207 : requiredDPI = requiredDPI * 96.0f;
147 : }
148 207 : cmp = DoCompare(actualDPI, requiredDPI);
149 : }
150 207 : break;
151 : case nsMediaFeature::eEnumerated:
152 : {
153 0 : NS_ASSERTION(actual.GetUnit() == eCSSUnit_Enumerated,
154 : "bad actual value");
155 0 : NS_ASSERTION(required.GetUnit() == eCSSUnit_Enumerated,
156 : "bad required value");
157 0 : NS_ASSERTION(mFeature->mRangeType == nsMediaFeature::eMinMaxNotAllowed,
158 : "bad range"); // we asserted above about mRange
159 : // We don't really need DoCompare, but it doesn't hurt (and
160 : // maybe the compiler will condense this case with eInteger).
161 0 : cmp = DoCompare(actual.GetIntValue(), required.GetIntValue());
162 : }
163 0 : break;
164 : case nsMediaFeature::eIdent:
165 : {
166 0 : NS_ASSERTION(actual.GetUnit() == eCSSUnit_Ident,
167 : "bad actual value");
168 0 : NS_ASSERTION(required.GetUnit() == eCSSUnit_Ident,
169 : "bad required value");
170 0 : NS_ASSERTION(mFeature->mRangeType == nsMediaFeature::eMinMaxNotAllowed,
171 : "bad range");
172 0 : cmp = !(actual == required); // string comparison
173 : }
174 0 : break;
175 : }
176 238 : switch (mRange) {
177 : case nsMediaExpression::eMin:
178 153 : return cmp != -1;
179 : case nsMediaExpression::eMax:
180 31 : return cmp != 1;
181 : case nsMediaExpression::eEqual:
182 54 : return cmp == 0;
183 : }
184 0 : NS_NOTREACHED("unexpected mRange");
185 0 : return false;
186 : }
187 :
188 : void
189 125 : nsMediaQueryResultCacheKey::AddExpression(const nsMediaExpression* aExpression,
190 : bool aExpressionMatches)
191 : {
192 125 : const nsMediaFeature *feature = aExpression->mFeature;
193 125 : FeatureEntry *entry = nullptr;
194 165 : for (uint32_t i = 0; i < mFeatureCache.Length(); ++i) {
195 128 : if (mFeatureCache[i].mFeature == feature) {
196 88 : entry = &mFeatureCache[i];
197 88 : break;
198 : }
199 : }
200 125 : if (!entry) {
201 37 : entry = mFeatureCache.AppendElement();
202 37 : if (!entry) {
203 0 : return; /* out of memory */
204 : }
205 37 : entry->mFeature = feature;
206 : }
207 :
208 250 : ExpressionEntry eentry = { *aExpression, aExpressionMatches };
209 125 : entry->mExpressions.AppendElement(eentry);
210 : }
211 :
212 : bool
213 136 : nsMediaQueryResultCacheKey::Matches(nsPresContext* aPresContext) const
214 : {
215 136 : if (aPresContext->Medium() != mMedium) {
216 0 : return false;
217 : }
218 :
219 292 : for (uint32_t i = 0; i < mFeatureCache.Length(); ++i) {
220 158 : const FeatureEntry *entry = &mFeatureCache[i];
221 314 : nsCSSValue actual;
222 :
223 158 : entry->mFeature->mGetter(aPresContext, entry->mFeature, actual);
224 :
225 402 : for (uint32_t j = 0; j < entry->mExpressions.Length(); ++j) {
226 246 : const ExpressionEntry &eentry = entry->mExpressions[j];
227 492 : if (eentry.mExpression.Matches(aPresContext, actual) !=
228 246 : eentry.mExpressionMatches) {
229 2 : return false;
230 : }
231 : }
232 : }
233 :
234 134 : return true;
235 : }
236 :
237 : bool
238 4 : nsDocumentRuleResultCacheKey::AddMatchingRule(css::DocumentRule* aRule)
239 : {
240 4 : MOZ_ASSERT(!mFinalized);
241 4 : return mMatchingRules.AppendElement(aRule);
242 : }
243 :
244 : void
245 10 : nsDocumentRuleResultCacheKey::Finalize()
246 : {
247 10 : mMatchingRules.Sort();
248 : #ifdef DEBUG
249 10 : mFinalized = true;
250 : #endif
251 10 : }
252 :
253 : #ifdef DEBUG
254 : static bool
255 48 : ArrayIsSorted(const nsTArray<css::DocumentRule*>& aRules)
256 : {
257 48 : for (size_t i = 1; i < aRules.Length(); i++) {
258 0 : if (aRules[i - 1] > aRules[i]) {
259 0 : return false;
260 : }
261 : }
262 48 : return true;
263 : }
264 : #endif
265 :
266 : bool
267 24 : nsDocumentRuleResultCacheKey::Matches(
268 : nsPresContext* aPresContext,
269 : const nsTArray<css::DocumentRule*>& aRules) const
270 : {
271 24 : MOZ_ASSERT(mFinalized);
272 24 : MOZ_ASSERT(ArrayIsSorted(mMatchingRules));
273 24 : MOZ_ASSERT(ArrayIsSorted(aRules));
274 :
275 : #ifdef DEBUG
276 24 : for (css::DocumentRule* rule : mMatchingRules) {
277 0 : MOZ_ASSERT(aRules.BinaryIndexOf(rule) != aRules.NoIndex,
278 : "aRules must contain all rules in mMatchingRules");
279 : }
280 : #endif
281 :
282 : // First check that aPresContext matches all the rules listed in
283 : // mMatchingRules.
284 24 : for (css::DocumentRule* rule : mMatchingRules) {
285 0 : if (!rule->UseForPresentation(aPresContext)) {
286 0 : return false;
287 : }
288 : }
289 :
290 : // Then check that all the rules in aRules that aren't also in
291 : // mMatchingRules do not match.
292 :
293 : // pointer to matching rules
294 24 : auto pm = mMatchingRules.begin();
295 24 : auto pm_end = mMatchingRules.end();
296 :
297 : // pointer to all rules
298 24 : auto pr = aRules.begin();
299 24 : auto pr_end = aRules.end();
300 :
301 : // mMatchingRules and aRules are both sorted by their pointer values,
302 : // so we can iterate over the two lists simultaneously.
303 30 : while (pr < pr_end) {
304 3 : while (pm < pm_end && *pm < *pr) {
305 0 : ++pm;
306 : }
307 3 : if (pm >= pm_end || *pm != *pr) {
308 3 : if ((*pr)->UseForPresentation(aPresContext)) {
309 0 : return false;
310 : }
311 : }
312 3 : ++pr;
313 : }
314 24 : return true;
315 : }
316 :
317 : #ifdef DEBUG
318 : void
319 0 : nsDocumentRuleResultCacheKey::List(FILE* aOut, int32_t aIndent) const
320 : {
321 0 : for (css::DocumentRule* rule : mMatchingRules) {
322 0 : nsCString str;
323 :
324 0 : for (int32_t i = 0; i < aIndent; i++) {
325 0 : str.AppendLiteral(" ");
326 : }
327 0 : str.AppendLiteral("{ ");
328 :
329 0 : nsString condition;
330 0 : rule->GetConditionText(condition);
331 0 : AppendUTF16toUTF8(condition, str);
332 :
333 0 : str.AppendLiteral(" }\n");
334 0 : fprintf_stderr(aOut, "%s", str.get());
335 : }
336 0 : }
337 : #endif
338 :
339 : size_t
340 0 : nsDocumentRuleResultCacheKey::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
341 : {
342 0 : size_t n = 0;
343 0 : n += mMatchingRules.ShallowSizeOfExcludingThis(aMallocSizeOf);
344 0 : return n;
345 : }
346 :
347 : void
348 0 : nsMediaQuery::AppendToString(nsAString& aString) const
349 : {
350 0 : if (mHadUnknownExpression) {
351 0 : aString.AppendLiteral("not all");
352 0 : return;
353 : }
354 :
355 0 : NS_ASSERTION(!mNegated || !mHasOnly, "can't have not and only");
356 0 : NS_ASSERTION(!mTypeOmitted || (!mNegated && !mHasOnly),
357 : "can't have not or only when type is omitted");
358 0 : if (!mTypeOmitted) {
359 0 : if (mNegated) {
360 0 : aString.AppendLiteral("not ");
361 0 : } else if (mHasOnly) {
362 0 : aString.AppendLiteral("only ");
363 : }
364 0 : aString.Append(nsDependentAtomString(mMediaType));
365 : }
366 :
367 0 : for (uint32_t i = 0, i_end = mExpressions.Length(); i < i_end; ++i) {
368 0 : if (i > 0 || !mTypeOmitted)
369 0 : aString.AppendLiteral(" and ");
370 0 : aString.Append('(');
371 :
372 0 : const nsMediaExpression &expr = mExpressions[i];
373 0 : const nsMediaFeature *feature = expr.mFeature;
374 0 : if (feature->mReqFlags & nsMediaFeature::eHasWebkitPrefix) {
375 0 : aString.AppendLiteral("-webkit-");
376 : }
377 0 : if (expr.mRange == nsMediaExpression::eMin) {
378 0 : aString.AppendLiteral("min-");
379 0 : } else if (expr.mRange == nsMediaExpression::eMax) {
380 0 : aString.AppendLiteral("max-");
381 : }
382 :
383 0 : aString.Append(nsDependentAtomString(*feature->mName));
384 :
385 0 : if (expr.mValue.GetUnit() != eCSSUnit_Null) {
386 0 : aString.AppendLiteral(": ");
387 0 : switch (feature->mValueType) {
388 : case nsMediaFeature::eLength:
389 0 : NS_ASSERTION(expr.mValue.IsLengthUnit(), "bad unit");
390 : // Use 'width' as a property that takes length values
391 : // written in the normal way.
392 0 : expr.mValue.AppendToString(eCSSProperty_width, aString,
393 0 : nsCSSValue::eNormalized);
394 0 : break;
395 : case nsMediaFeature::eInteger:
396 : case nsMediaFeature::eBoolInteger:
397 0 : NS_ASSERTION(expr.mValue.GetUnit() == eCSSUnit_Integer,
398 : "bad unit");
399 : // Use 'z-index' as a property that takes integer values
400 : // written without anything extra.
401 0 : expr.mValue.AppendToString(eCSSProperty_z_index, aString,
402 0 : nsCSSValue::eNormalized);
403 0 : break;
404 : case nsMediaFeature::eFloat:
405 : {
406 0 : NS_ASSERTION(expr.mValue.GetUnit() == eCSSUnit_Number,
407 : "bad unit");
408 : // Use 'line-height' as a property that takes float values
409 : // written in the normal way.
410 0 : expr.mValue.AppendToString(eCSSProperty_line_height, aString,
411 0 : nsCSSValue::eNormalized);
412 : }
413 0 : break;
414 : case nsMediaFeature::eIntRatio:
415 : {
416 0 : NS_ASSERTION(expr.mValue.GetUnit() == eCSSUnit_Array,
417 : "bad unit");
418 0 : nsCSSValue::Array *array = expr.mValue.GetArrayValue();
419 0 : NS_ASSERTION(array->Count() == 2, "unexpected length");
420 0 : NS_ASSERTION(array->Item(0).GetUnit() == eCSSUnit_Integer,
421 : "bad unit");
422 0 : NS_ASSERTION(array->Item(1).GetUnit() == eCSSUnit_Integer,
423 : "bad unit");
424 0 : array->Item(0).AppendToString(eCSSProperty_z_index, aString,
425 0 : nsCSSValue::eNormalized);
426 0 : aString.Append('/');
427 0 : array->Item(1).AppendToString(eCSSProperty_z_index, aString,
428 0 : nsCSSValue::eNormalized);
429 : }
430 0 : break;
431 : case nsMediaFeature::eResolution:
432 : {
433 0 : aString.AppendFloat(expr.mValue.GetFloatValue());
434 0 : if (expr.mValue.GetUnit() == eCSSUnit_Inch) {
435 0 : aString.AppendLiteral("dpi");
436 0 : } else if (expr.mValue.GetUnit() == eCSSUnit_Pixel) {
437 0 : aString.AppendLiteral("dppx");
438 : } else {
439 0 : NS_ASSERTION(expr.mValue.GetUnit() == eCSSUnit_Centimeter,
440 : "bad unit");
441 0 : aString.AppendLiteral("dpcm");
442 : }
443 : }
444 0 : break;
445 : case nsMediaFeature::eEnumerated:
446 0 : NS_ASSERTION(expr.mValue.GetUnit() == eCSSUnit_Enumerated,
447 : "bad unit");
448 0 : AppendASCIItoUTF16(
449 : nsCSSProps::ValueToKeyword(expr.mValue.GetIntValue(),
450 0 : feature->mData.mKeywordTable),
451 0 : aString);
452 0 : break;
453 : case nsMediaFeature::eIdent:
454 0 : NS_ASSERTION(expr.mValue.GetUnit() == eCSSUnit_Ident,
455 : "bad unit");
456 0 : aString.Append(expr.mValue.GetStringBufferValue());
457 0 : break;
458 : }
459 : }
460 :
461 0 : aString.Append(')');
462 : }
463 : }
464 :
465 : nsMediaQuery*
466 0 : nsMediaQuery::Clone() const
467 : {
468 0 : return new nsMediaQuery(*this);
469 : }
470 :
471 : bool
472 153 : nsMediaQuery::Matches(nsPresContext* aPresContext,
473 : nsMediaQueryResultCacheKey* aKey) const
474 : {
475 153 : if (mHadUnknownExpression)
476 0 : return false;
477 :
478 : bool match =
479 153 : mMediaType == aPresContext->Medium() || mMediaType == nsGkAtoms::all;
480 282 : for (uint32_t i = 0, i_end = mExpressions.Length(); match && i < i_end; ++i) {
481 129 : const nsMediaExpression &expr = mExpressions[i];
482 258 : nsCSSValue actual;
483 129 : expr.mFeature->mGetter(aPresContext, expr.mFeature, actual);
484 :
485 129 : match = expr.Matches(aPresContext, actual);
486 129 : if (aKey) {
487 125 : aKey->AddExpression(&expr, match);
488 : }
489 : }
490 :
491 153 : return match == !mNegated;
492 : }
493 :
494 54 : nsMediaList::nsMediaList()
495 : {
496 54 : }
497 :
498 0 : nsMediaList::~nsMediaList()
499 : {
500 0 : }
501 :
502 : void
503 0 : nsMediaList::GetText(nsAString& aMediaText)
504 : {
505 0 : aMediaText.Truncate();
506 :
507 0 : for (int32_t i = 0, i_end = mArray.Length(); i < i_end; ++i) {
508 0 : nsMediaQuery* query = mArray[i];
509 :
510 0 : query->AppendToString(aMediaText);
511 :
512 0 : if (i + 1 < i_end) {
513 0 : aMediaText.AppendLiteral(", ");
514 : }
515 : }
516 0 : }
517 :
518 : // XXXbz this is so ill-defined in the spec, it's not clear quite what
519 : // it should be doing....
520 : void
521 0 : nsMediaList::SetText(const nsAString& aMediaText)
522 : {
523 0 : nsCSSParser parser;
524 0 : parser.ParseMediaList(aMediaText, nullptr, 0, this);
525 0 : }
526 :
527 : bool
528 161 : nsMediaList::Matches(nsPresContext* aPresContext,
529 : nsMediaQueryResultCacheKey* aKey) const
530 : {
531 222 : for (int32_t i = 0, i_end = mArray.Length(); i < i_end; ++i) {
532 153 : if (mArray[i]->Matches(aPresContext, aKey)) {
533 92 : return true;
534 : }
535 : }
536 69 : return mArray.IsEmpty();
537 : }
538 :
539 : already_AddRefed<dom::MediaList>
540 0 : nsMediaList::Clone()
541 : {
542 0 : RefPtr<nsMediaList> result = new nsMediaList();
543 0 : result->mArray.AppendElements(mArray.Length());
544 0 : for (uint32_t i = 0, i_end = mArray.Length(); i < i_end; ++i) {
545 0 : result->mArray[i] = mArray[i]->Clone();
546 0 : MOZ_ASSERT(result->mArray[i]);
547 : }
548 0 : return result.forget();
549 : }
550 :
551 : void
552 0 : nsMediaList::IndexedGetter(uint32_t aIndex, bool& aFound, nsAString& aReturn)
553 : {
554 0 : if (aIndex < Length()) {
555 0 : aFound = true;
556 0 : aReturn.Truncate();
557 0 : mArray[aIndex]->AppendToString(aReturn);
558 : } else {
559 0 : aFound = false;
560 0 : SetDOMStringToNull(aReturn);
561 : }
562 0 : }
563 :
564 : nsresult
565 0 : nsMediaList::Delete(const nsAString& aOldMedium)
566 : {
567 0 : if (aOldMedium.IsEmpty())
568 0 : return NS_ERROR_DOM_NOT_FOUND_ERR;
569 :
570 0 : for (int32_t i = 0, i_end = mArray.Length(); i < i_end; ++i) {
571 0 : nsMediaQuery* query = mArray[i];
572 :
573 0 : nsAutoString buf;
574 0 : query->AppendToString(buf);
575 0 : if (buf == aOldMedium) {
576 0 : mArray.RemoveElementAt(i);
577 0 : return NS_OK;
578 : }
579 : }
580 :
581 0 : return NS_ERROR_DOM_NOT_FOUND_ERR;
582 : }
583 :
584 : nsresult
585 0 : nsMediaList::Append(const nsAString& aNewMedium)
586 : {
587 0 : if (aNewMedium.IsEmpty())
588 0 : return NS_ERROR_DOM_NOT_FOUND_ERR;
589 :
590 0 : Delete(aNewMedium);
591 :
592 0 : nsresult rv = NS_OK;
593 0 : nsTArray<nsAutoPtr<nsMediaQuery> > buf;
594 0 : mArray.SwapElements(buf);
595 0 : SetText(aNewMedium);
596 0 : if (mArray.Length() == 1) {
597 0 : nsMediaQuery *query = mArray[0].forget();
598 0 : if (!buf.AppendElement(query)) {
599 0 : delete query;
600 0 : rv = NS_ERROR_OUT_OF_MEMORY;
601 : }
602 : }
603 :
604 0 : mArray.SwapElements(buf);
605 0 : return rv;
606 : }
|