~ubuntu-branches/ubuntu/precise/kompozer/precise

« back to all changes in this revision

Viewing changes to mozilla/content/base/src/nsAttrValue.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Anthony Yarusso
  • Date: 2007-08-27 01:11:03 UTC
  • Revision ID: james.westby@ubuntu.com-20070827011103-2jgf4s6532gqu2ka
Tags: upstream-0.7.10
ImportĀ upstreamĀ versionĀ 0.7.10

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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.org code.
 
16
 *
 
17
 * The Initial Developer of the Original Code is
 
18
 * IBM Corporation.
 
19
 * Portions created by the Initial Developer are Copyright (C) 2003
 
20
 * IBM Corporation. All Rights Reserved.
 
21
 *
 
22
 * Contributor(s):
 
23
 *   IBM Corporation
 
24
 *
 
25
 * Alternatively, the contents of this file may be used under the terms of
 
26
 * either the GNU General Public License Version 2 or later (the "GPL"), or
 
27
 * 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 "nsAttrValue.h"
 
40
#include "nsHTMLValue.h"
 
41
#include "nsIAtom.h"
 
42
#include "nsUnicharUtils.h"
 
43
#include "nsICSSStyleRule.h"
 
44
#include "nsCSSDeclaration.h"
 
45
#include "nsIHTMLDocument.h"
 
46
#include "nsIDocument.h"
 
47
 
 
48
#ifdef MOZ_SVG
 
49
#include "nsISVGValue.h"
 
50
#endif
 
51
 
 
52
nsAttrValue::nsAttrValue()
 
53
    : mBits(0)
 
54
{
 
55
}
 
56
 
 
57
nsAttrValue::nsAttrValue(const nsAttrValue& aOther)
 
58
    : mBits(0)
 
59
{
 
60
  SetTo(aOther);
 
61
}
 
62
 
 
63
nsAttrValue::nsAttrValue(const nsAString& aValue)
 
64
    : mBits(0)
 
65
{
 
66
  SetTo(aValue);
 
67
}
 
68
 
 
69
nsAttrValue::nsAttrValue(nsICSSStyleRule* aValue)
 
70
    : mBits(0)
 
71
{
 
72
  SetTo(aValue);
 
73
}
 
74
 
 
75
#ifdef MOZ_SVG
 
76
nsAttrValue::nsAttrValue(nsISVGValue* aValue)
 
77
    : mBits(0)
 
78
{
 
79
  SetTo(aValue);
 
80
}
 
81
#endif
 
82
 
 
83
nsAttrValue::~nsAttrValue()
 
84
{
 
85
  ResetIfSet();
 
86
}
 
87
 
 
88
nsAttrValue::ValueType
 
89
nsAttrValue::Type() const
 
90
{
 
91
  switch (BaseType()) {
 
92
    case eIntegerBase:
 
93
    {
 
94
      return NS_STATIC_CAST(ValueType, mBits & NS_ATTRVALUE_INTEGERTYPE_MASK);
 
95
    }
 
96
    case eOtherBase:
 
97
    {
 
98
      return GetMiscContainer()->mType;
 
99
    }
 
100
    default:
 
101
    {
 
102
      return NS_STATIC_CAST(ValueType, NS_STATIC_CAST(PRUint16, BaseType()));
 
103
    }
 
104
  }
 
105
}
 
106
 
 
107
void
 
108
nsAttrValue::Reset()
 
109
{
 
110
  switch(BaseType()) {
 
111
    case eStringBase:
 
112
    {
 
113
      PRUnichar* str = NS_STATIC_CAST(PRUnichar*, GetPtr());
 
114
      if (str) {
 
115
        nsCheapStringBufferUtils::Free(str);
 
116
      }
 
117
 
 
118
      break;
 
119
    }
 
120
    case eOtherBase:
 
121
    {
 
122
      EnsureEmptyMiscContainer();
 
123
      delete GetMiscContainer();
 
124
 
 
125
      break;
 
126
    }
 
127
    case eAtomBase:
 
128
    {
 
129
      nsIAtom* atom = GetAtomValue();
 
130
      NS_RELEASE(atom);
 
131
 
 
132
      break;
 
133
    }
 
134
    case eIntegerBase:
 
135
    {
 
136
      break;
 
137
    }
 
138
  }
 
139
 
 
140
  mBits = 0;
 
141
}
 
142
 
 
143
void
 
144
nsAttrValue::SetTo(const nsAttrValue& aOther)
 
145
{
 
146
  switch (aOther.BaseType()) {
 
147
    case eStringBase:
 
148
    {
 
149
      SetTo(aOther.GetStringValue());
 
150
      return;
 
151
    }
 
152
    case eOtherBase:
 
153
    {
 
154
      break;
 
155
    }
 
156
    case eAtomBase:
 
157
    {
 
158
      ResetIfSet();
 
159
      nsIAtom* atom = aOther.GetAtomValue();
 
160
      NS_ADDREF(atom);
 
161
      SetPtrValueAndType(atom, eAtomBase);
 
162
      return;
 
163
    }
 
164
    case eIntegerBase:
 
165
    {
 
166
      ResetIfSet();
 
167
      mBits = aOther.mBits;
 
168
      return;      
 
169
    }
 
170
  }
 
171
 
 
172
  MiscContainer* otherCont = aOther.GetMiscContainer();
 
173
  switch (otherCont->mType) {
 
174
    case eColor:
 
175
    {
 
176
      if (EnsureEmptyMiscContainer()) {
 
177
        MiscContainer* cont = GetMiscContainer();
 
178
        cont->mColor = otherCont->mColor;
 
179
        cont->mType = eColor;
 
180
      }
 
181
      break;
 
182
    }
 
183
    case eCSSStyleRule:
 
184
    {
 
185
      SetTo(otherCont->mCSSStyleRule);
 
186
      break;
 
187
    }
 
188
    case eAtomArray:
 
189
    {
 
190
      if (!EnsureEmptyAtomArray() ||
 
191
          !GetAtomArrayValue()->AppendObjects(*otherCont->mAtomArray)) {
 
192
        Reset();
 
193
      }
 
194
      break;
 
195
    }
 
196
#ifdef MOZ_SVG
 
197
    case eSVGValue:
 
198
    {
 
199
      SetTo(otherCont->mSVGValue);
 
200
    }
 
201
#endif
 
202
    default:
 
203
    {
 
204
      NS_NOTREACHED("unknown type stored in MiscContainer");
 
205
      break;
 
206
    }
 
207
  }
 
208
}
 
209
 
 
210
void
 
211
nsAttrValue::SetTo(const nsAString& aValue)
 
212
{
 
213
  PRUnichar* str = nsnull;
 
214
  PRBool empty = aValue.IsEmpty();
 
215
  void* ptr;
 
216
  if (BaseType() == eStringBase && (ptr = GetPtr())) {
 
217
    if (!empty) {
 
218
      nsCheapStringBufferUtils::
 
219
        CopyToExistingBuffer(str, NS_STATIC_CAST(PRUnichar*, ptr), aValue);
 
220
    }
 
221
    else {
 
222
      nsCheapStringBufferUtils::Free(NS_STATIC_CAST(PRUnichar*, ptr));
 
223
    }
 
224
  }
 
225
  else {
 
226
    ResetIfSet();
 
227
    if (!empty) {
 
228
      nsCheapStringBufferUtils::CopyToBuffer(str, aValue);
 
229
    }
 
230
  }
 
231
  SetPtrValueAndType(str, eStringBase);
 
232
}
 
233
 
 
234
void
 
235
nsAttrValue::SetTo(PRInt16 aInt, ValueType aType)
 
236
{
 
237
  ResetIfSet();
 
238
  SetIntValueAndType(aInt, aType);
 
239
}
 
240
 
 
241
void
 
242
nsAttrValue::SetTo(nsICSSStyleRule* aValue)
 
243
{
 
244
  if (EnsureEmptyMiscContainer()) {
 
245
    MiscContainer* cont = GetMiscContainer();
 
246
    NS_ADDREF(cont->mCSSStyleRule = aValue);
 
247
    cont->mType = eCSSStyleRule;
 
248
  }
 
249
}
 
250
 
 
251
#ifdef MOZ_SVG
 
252
void
 
253
nsAttrValue::SetTo(nsISVGValue* aValue)
 
254
{
 
255
  if (EnsureEmptyMiscContainer()) {
 
256
    MiscContainer* cont = GetMiscContainer();
 
257
    NS_ADDREF(cont->mSVGValue = aValue);
 
258
    cont->mType = eSVGValue;
 
259
  }
 
260
}
 
261
#endif
 
262
 
 
263
void
 
264
nsAttrValue::SwapValueWith(nsAttrValue& aOther)
 
265
{
 
266
  PtrBits tmp = aOther.mBits;
 
267
  aOther.mBits = mBits;
 
268
  mBits = tmp;
 
269
}
 
270
 
 
271
void
 
272
nsAttrValue::ToString(nsAString& aResult) const
 
273
{
 
274
  switch(Type()) {
 
275
    case eString:
 
276
    {
 
277
      PRUnichar* str = NS_STATIC_CAST(PRUnichar*, GetPtr());
 
278
      if (str) {
 
279
        aResult = nsCheapStringBufferUtils::GetDependentString(str);
 
280
      }
 
281
      else {
 
282
        aResult.Truncate();
 
283
      }
 
284
      break;
 
285
    }
 
286
    case eAtom:
 
287
    {
 
288
      NS_STATIC_CAST(nsIAtom*, GetPtr())->ToString(aResult);
 
289
 
 
290
      break;
 
291
    }
 
292
    case eInteger:
 
293
    {
 
294
      nsAutoString intStr;
 
295
      intStr.AppendInt(GetIntInternal());
 
296
      aResult = intStr;
 
297
 
 
298
      break;
 
299
    }
 
300
    case eColor:
 
301
    {
 
302
      nscolor v;
 
303
      GetColorValue(v);
 
304
      NS_RGBToHex(v, aResult);
 
305
 
 
306
      break;
 
307
    }
 
308
    case eProportional:
 
309
    {
 
310
      nsAutoString intStr;
 
311
      intStr.AppendInt(GetIntInternal());
 
312
      aResult = intStr + NS_LITERAL_STRING("*");
 
313
 
 
314
      break;
 
315
    }
 
316
    case eEnum:
 
317
    {
 
318
      NS_NOTREACHED("trying to convert enum to string");
 
319
 
 
320
      break;
 
321
    }
 
322
    case ePercent:
 
323
    {
 
324
      nsAutoString intStr;
 
325
      intStr.AppendInt(GetIntInternal());
 
326
      aResult = intStr + NS_LITERAL_STRING("%");
 
327
 
 
328
      break;
 
329
    }
 
330
    case eCSSStyleRule:
 
331
    {
 
332
      aResult.Truncate();
 
333
      nsCSSDeclaration* decl = 
 
334
        GetMiscContainer()->mCSSStyleRule->GetDeclaration();
 
335
      if (decl) {
 
336
        decl->ToString(aResult);
 
337
      }
 
338
 
 
339
      break;
 
340
    }
 
341
    case eAtomArray:
 
342
    {
 
343
      MiscContainer* cont = GetMiscContainer();
 
344
      PRInt32 count = cont->mAtomArray->Count();
 
345
      if (count) {
 
346
        cont->mAtomArray->ObjectAt(0)->ToString(aResult);
 
347
        nsAutoString tmp;
 
348
        PRInt32 i;
 
349
        for (i = 1; i < count; ++i) {
 
350
          cont->mAtomArray->ObjectAt(i)->ToString(tmp);
 
351
          aResult.Append(NS_LITERAL_STRING(" ") + tmp);
 
352
        }
 
353
      }
 
354
      else {
 
355
        aResult.Truncate();
 
356
      }
 
357
      break;
 
358
    }
 
359
#ifdef MOZ_SVG
 
360
    case eSVGValue:
 
361
    {
 
362
      GetMiscContainer()->mSVGValue->GetValueString(aResult);
 
363
    }
 
364
#endif
 
365
  }
 
366
}
 
367
 
 
368
void
 
369
nsAttrValue::ToHTMLValue(nsHTMLValue& aResult) const
 
370
{
 
371
  switch(Type()) {
 
372
    case eString:
 
373
    {
 
374
      aResult.SetStringValue(GetStringValue());
 
375
      break;
 
376
    }
 
377
    case eAtom:
 
378
    {
 
379
      nsAutoString tmp;
 
380
      GetAtomValue()->ToString(tmp);
 
381
      aResult.SetStringValue(tmp);
 
382
      break;
 
383
    }
 
384
    case eInteger:
 
385
    {
 
386
      aResult.SetIntValue(GetIntInternal(), eHTMLUnit_Integer);
 
387
      break;
 
388
    }
 
389
    case eColor:
 
390
    {
 
391
      nscolor v;
 
392
      GetColorValue(v);
 
393
      aResult.SetColorValue(v);
 
394
      break;
 
395
    }
 
396
    case eProportional:
 
397
    {
 
398
      aResult.SetIntValue(GetProportionalValue(), eHTMLUnit_Proportional);
 
399
      break;
 
400
    }
 
401
    case eEnum:
 
402
    {
 
403
      aResult.SetIntValue(GetEnumValue(), eHTMLUnit_Enumerated);
 
404
      break;
 
405
    }
 
406
    case ePercent:
 
407
    {
 
408
      aResult.SetPercentValue(GetPercentValue());
 
409
      break;
 
410
    }
 
411
    case eCSSStyleRule:
 
412
    {
 
413
      aResult.SetCSSStyleRuleValue(GetCSSStyleRuleValue());
 
414
      break;
 
415
    }
 
416
    case eAtomArray:
 
417
    {
 
418
      nsCOMArray<nsIAtom>* array = new nsCOMArray<nsIAtom>(*GetAtomArrayValue());
 
419
      aResult.SetAtomArrayValue(array);
 
420
      break;
 
421
    }
 
422
#ifdef MOZ_SVG
 
423
    case eSVGValue:
 
424
    {
 
425
      nsAutoString tmp;
 
426
      GetSVGValue()->GetValueString(tmp);
 
427
      aResult.SetStringValue(tmp);
 
428
    }
 
429
#endif
 
430
  }
 
431
}
 
432
 
 
433
const nsDependentSubstring
 
434
nsAttrValue::GetStringValue() const
 
435
{
 
436
  NS_PRECONDITION(Type() == eString, "wrong type");
 
437
 
 
438
  static const PRUnichar blankStr[] = { '\0' };
 
439
  void* ptr = GetPtr();
 
440
  return ptr
 
441
         ? nsCheapStringBufferUtils::GetDependentString(NS_STATIC_CAST(PRUnichar*, ptr))
 
442
         : Substring(blankStr, blankStr);
 
443
}
 
444
 
 
445
PRBool
 
446
nsAttrValue::GetColorValue(nscolor& aColor) const
 
447
{
 
448
  NS_PRECONDITION(Type() == eColor || Type() == eString, "wrong type");
 
449
  switch (BaseType()) {
 
450
    case eString:
 
451
    {
 
452
      return GetPtr() && NS_ColorNameToRGB(GetStringValue(), &aColor);
 
453
    }
 
454
    case eOtherBase:
 
455
    {
 
456
      aColor = GetMiscContainer()->mColor;
 
457
      
 
458
      break;
 
459
    }
 
460
    case eIntegerBase:
 
461
    {
 
462
      aColor = NS_STATIC_CAST(nscolor, GetIntInternal());
 
463
      
 
464
      break;
 
465
    }
 
466
    default:
 
467
    {
 
468
      NS_NOTREACHED("unexpected basetype");
 
469
      
 
470
      break;
 
471
    }
 
472
  }
 
473
 
 
474
  return PR_TRUE;
 
475
}
 
476
 
 
477
PRInt32
 
478
nsAttrValue::GetAtomCount() const
 
479
{
 
480
  ValueType type = Type();
 
481
 
 
482
  if (type == eAtom) {
 
483
    return 1;
 
484
  }
 
485
 
 
486
  if (type == eAtomArray) {
 
487
    return GetAtomArrayValue()->Count();
 
488
  }
 
489
 
 
490
  return 0;
 
491
}
 
492
 
 
493
nsIAtom*
 
494
nsAttrValue::AtomAt(PRInt32 aIndex) const
 
495
{
 
496
  NS_PRECONDITION(aIndex >= 0, "Index must not be negative");
 
497
  NS_PRECONDITION(GetAtomCount() > aIndex, "aIndex out of range");
 
498
  
 
499
  if (BaseType() == eAtomBase) {
 
500
    return GetAtomValue();
 
501
  }
 
502
 
 
503
  NS_ASSERTION(Type() == eAtomArray, "GetAtomCount must be confused");
 
504
  
 
505
  return GetAtomArrayValue()->ObjectAt(aIndex);
 
506
}
 
507
 
 
508
PRUint32
 
509
nsAttrValue::HashValue() const
 
510
{
 
511
  switch(BaseType()) {
 
512
    case eStringBase:
 
513
    {
 
514
      PRUnichar* str = NS_STATIC_CAST(PRUnichar*, GetPtr());
 
515
      return str ? nsCheapStringBufferUtils::HashCode(str) : 0;
 
516
    }
 
517
    case eOtherBase:
 
518
    {
 
519
      break;
 
520
    }
 
521
    case eAtomBase:
 
522
    case eIntegerBase:
 
523
    {
 
524
      // mBits and PRUint32 might have different size. This should silence
 
525
      // any warnings or compile-errors. This is what the implementation of
 
526
      // NS_PTR_TO_INT32 does to take care of the same problem.
 
527
      return mBits - 0;
 
528
    }
 
529
  }
 
530
 
 
531
  MiscContainer* cont = GetMiscContainer();
 
532
  switch (cont->mType) {
 
533
    case eColor:
 
534
    {
 
535
      return cont->mColor;
 
536
    }
 
537
    case eCSSStyleRule:
 
538
    {
 
539
      return NS_PTR_TO_INT32(cont->mCSSStyleRule);
 
540
    }
 
541
    case eAtomArray:
 
542
    {
 
543
      PRUint32 retval = 0;
 
544
      PRInt32 i, count = cont->mAtomArray->Count();
 
545
      for (i = 0; i < count; ++i) {
 
546
        retval ^= NS_PTR_TO_INT32(cont->mAtomArray->ObjectAt(i));
 
547
      }
 
548
      return retval;
 
549
    }
 
550
#ifdef MOZ_SVG
 
551
    case eSVGValue:
 
552
    {
 
553
      return NS_PTR_TO_INT32(cont->mSVGValue);
 
554
    }
 
555
#endif
 
556
    default:
 
557
    {
 
558
      NS_NOTREACHED("unknown type stored in MiscContainer");
 
559
      return 0;
 
560
    }
 
561
  }
 
562
}
 
563
 
 
564
PRBool
 
565
nsAttrValue::Equals(const nsAttrValue& aOther) const
 
566
{
 
567
  if (BaseType() != aOther.BaseType()) {
 
568
    return PR_FALSE;
 
569
  }
 
570
 
 
571
  switch(BaseType()) {
 
572
    case eStringBase:
 
573
    {
 
574
      return GetStringValue().Equals(aOther.GetStringValue());
 
575
    }
 
576
    case eOtherBase:
 
577
    {
 
578
      break;
 
579
    }
 
580
    case eAtomBase:
 
581
    case eIntegerBase:
 
582
    {
 
583
      return mBits == aOther.mBits;
 
584
    }
 
585
  }
 
586
 
 
587
  MiscContainer* thisCont = GetMiscContainer();
 
588
  MiscContainer* otherCont = aOther.GetMiscContainer();
 
589
  if (thisCont->mType != otherCont->mType) {
 
590
    return PR_FALSE;
 
591
  }
 
592
 
 
593
  switch (thisCont->mType) {
 
594
    case eColor:
 
595
    {
 
596
      return thisCont->mColor == otherCont->mColor;
 
597
    }
 
598
    case eCSSStyleRule:
 
599
    {
 
600
      return thisCont->mCSSStyleRule == otherCont->mCSSStyleRule;
 
601
    }
 
602
    case eAtomArray:
 
603
    {
 
604
      // For classlists we could be insensitive to order, however
 
605
      // classlists are never mapped attributes so they are never compared.
 
606
 
 
607
      PRInt32 count = thisCont->mAtomArray->Count();
 
608
      if (count != otherCont->mAtomArray->Count()) {
 
609
        return PR_FALSE;
 
610
      }
 
611
 
 
612
      PRInt32 i;
 
613
      for (i = 0; i < count; ++i) {
 
614
        if (thisCont->mAtomArray->ObjectAt(i) !=
 
615
            otherCont->mAtomArray->ObjectAt(i)) {
 
616
          return PR_FALSE;
 
617
        }
 
618
      }
 
619
      return PR_TRUE;
 
620
    }
 
621
#ifdef MOZ_SVG
 
622
    case eSVGValue:
 
623
    {
 
624
      return thisCont->mSVGValue == otherCont->mSVGValue;
 
625
    }
 
626
#endif
 
627
    default:
 
628
    {
 
629
      NS_NOTREACHED("unknown type stored in MiscContainer");
 
630
      return PR_FALSE;
 
631
    }
 
632
  }
 
633
}
 
634
 
 
635
void
 
636
nsAttrValue::ParseAtom(const nsAString& aValue)
 
637
{
 
638
  ResetIfSet();
 
639
 
 
640
  nsIAtom* atom = NS_NewAtom(aValue);
 
641
  if (atom) {
 
642
    SetPtrValueAndType(atom, eAtomBase);
 
643
  }
 
644
}
 
645
 
 
646
void
 
647
nsAttrValue::ParseAtomArray(const nsAString& aValue)
 
648
{
 
649
  nsAString::const_iterator iter, end;
 
650
  aValue.BeginReading(iter);
 
651
  aValue.EndReading(end);
 
652
 
 
653
  // skip initial whitespace
 
654
  while (iter != end && nsCRT::IsAsciiSpace(*iter)) {
 
655
    ++iter;
 
656
  }
 
657
 
 
658
  if (iter == end) {
 
659
    ResetIfSet();
 
660
    return;
 
661
  }
 
662
 
 
663
  nsAString::const_iterator start(iter);
 
664
 
 
665
  // get first - and often only - atom
 
666
  do {
 
667
    ++iter;
 
668
  } while (iter != end && !nsCRT::IsAsciiSpace(*iter));
 
669
 
 
670
  nsCOMPtr<nsIAtom> classAtom = do_GetAtom(Substring(start, iter));
 
671
  if (!classAtom) {
 
672
    Reset();
 
673
    return;
 
674
  }
 
675
 
 
676
  // skip whitespace
 
677
  while (iter != end && nsCRT::IsAsciiSpace(*iter)) {
 
678
    ++iter;
 
679
  }
 
680
 
 
681
  if (iter == end) {
 
682
    // we only found one classname so don't bother storing a list
 
683
    ResetIfSet();
 
684
    nsIAtom* atom = nsnull;
 
685
    classAtom.swap(atom);
 
686
    SetPtrValueAndType(atom, eAtomBase);
 
687
    return;
 
688
  }
 
689
 
 
690
  if (!EnsureEmptyAtomArray()) {
 
691
    return;
 
692
  }
 
693
 
 
694
  nsCOMArray<nsIAtom>* array = GetAtomArrayValue();
 
695
  
 
696
  if (!array->AppendObject(classAtom)) {
 
697
    Reset();
 
698
    return;
 
699
  }
 
700
 
 
701
  // parse the rest of the classnames
 
702
  do {
 
703
    start = iter;
 
704
 
 
705
    do {
 
706
      ++iter;
 
707
    } while (iter != end && !nsCRT::IsAsciiSpace(*iter));
 
708
 
 
709
    classAtom = do_GetAtom(Substring(start, iter));
 
710
 
 
711
    if (!array->AppendObject(classAtom)) {
 
712
      Reset();
 
713
      return;
 
714
    }
 
715
 
 
716
    // skip whitespace
 
717
    while (iter != end && nsCRT::IsAsciiSpace(*iter)) {
 
718
      ++iter;
 
719
    }
 
720
  } while (iter != end);
 
721
 
 
722
  return;
 
723
}
 
724
 
 
725
void
 
726
nsAttrValue::ParseStringOrAtom(const nsAString& aValue)
 
727
{
 
728
  PRUint32 len = aValue.Length();
 
729
  // Don't bother with atoms if it's an empty string since
 
730
  // we can store those efficently anyway.
 
731
  if (len && len <= NS_ATTRVALUE_MAX_STRINGLENGTH_ATOM) {
 
732
    ParseAtom(aValue);
 
733
  }
 
734
  else {
 
735
    SetTo(aValue);
 
736
  }
 
737
}
 
738
 
 
739
PRBool
 
740
nsAttrValue::ParseEnumValue(const nsAString& aValue,
 
741
                            const nsHTMLValue::EnumTable* aTable,
 
742
                            PRBool aCaseSensitive)
 
743
{
 
744
  ResetIfSet();
 
745
 
 
746
  nsAutoString val(aValue);
 
747
  while (aTable->tag) {
 
748
    if (aCaseSensitive ? val.EqualsWithConversion(aTable->tag) :
 
749
                         val.EqualsIgnoreCase(aTable->tag)) {
 
750
      SetIntValueAndType(aTable->value, eEnum);
 
751
 
 
752
      return PR_TRUE;
 
753
    }
 
754
    aTable++;
 
755
  }
 
756
 
 
757
  return PR_FALSE;
 
758
}
 
759
 
 
760
PRBool
 
761
nsAttrValue::ParseSpecialIntValue(const nsAString& aString,
 
762
                                  PRBool aCanBePercent,
 
763
                                  PRBool aCanBeProportional)
 
764
{
 
765
  ResetIfSet();
 
766
 
 
767
  PRInt32 ec;
 
768
  nsAutoString tmp(aString);
 
769
  PRInt32 val = tmp.ToInteger(&ec);
 
770
 
 
771
  if (NS_FAILED(ec)) {
 
772
    if (aCanBeProportional) {
 
773
      // Even if the integer could not be parsed, it might just be "*"
 
774
      tmp.CompressWhitespace(PR_TRUE, PR_TRUE);
 
775
      if (tmp.Length() == 1 && tmp.Last() == '*') {
 
776
        // special case: HTML spec says a value '*' == '1*'
 
777
        // see http://www.w3.org/TR/html4/types.html#type-multi-length
 
778
        // bug 29061
 
779
        SetIntValueAndType(1, eProportional);
 
780
        return PR_TRUE;
 
781
      }
 
782
    }
 
783
    return PR_FALSE;
 
784
  }
 
785
 
 
786
  val = PR_MAX(val, 0);
 
787
  val = PR_MIN(val, NS_ATTRVALUE_INTEGERTYPE_MAXVALUE);
 
788
 
 
789
  // % (percent)
 
790
  // XXX RFindChar means that 5%x will be parsed!
 
791
  if (aCanBePercent && tmp.RFindChar('%') >= 0) {
 
792
    if (val > 100) {
 
793
      val = 100;
 
794
    }
 
795
    SetIntValueAndType(val, ePercent);
 
796
    return PR_TRUE;
 
797
  }
 
798
 
 
799
  // * (proportional) 
 
800
  // XXX RFindChar means that 5*x will be parsed!
 
801
  if (aCanBeProportional && tmp.RFindChar('*') >= 0) {
 
802
    SetIntValueAndType(val, eProportional);
 
803
    return PR_TRUE;
 
804
  }
 
805
 
 
806
  // Straight number is interpreted as integer
 
807
  SetIntValueAndType(val, eInteger);
 
808
  return PR_TRUE;
 
809
}
 
810
 
 
811
PRBool
 
812
nsAttrValue::ParseIntWithBounds(const nsAString& aString,
 
813
                                PRInt32 aMin, PRInt32 aMax)
 
814
{
 
815
  NS_PRECONDITION(aMin < aMax &&
 
816
                  aMin >= NS_ATTRVALUE_INTEGERTYPE_MINVALUE &&
 
817
                  aMax <= NS_ATTRVALUE_INTEGERTYPE_MAXVALUE, "bad boundaries");
 
818
 
 
819
  ResetIfSet();
 
820
 
 
821
  PRInt32 ec;
 
822
  PRInt32 val = PromiseFlatString(aString).ToInteger(&ec);
 
823
  if (NS_FAILED(ec)) {
 
824
    return PR_FALSE;
 
825
  }
 
826
 
 
827
  val = PR_MAX(val, aMin);
 
828
  val = PR_MIN(val, aMax);
 
829
  SetIntValueAndType(val, eInteger);
 
830
 
 
831
  return PR_TRUE;
 
832
}
 
833
 
 
834
PRBool
 
835
nsAttrValue::ParseColor(const nsAString& aString, nsIDocument* aDocument)
 
836
{
 
837
  nsAutoString colorStr(aString);
 
838
  colorStr.CompressWhitespace(PR_TRUE, PR_TRUE);
 
839
  if (colorStr.IsEmpty()) {
 
840
    Reset();
 
841
    return PR_FALSE;
 
842
  }
 
843
 
 
844
  nscolor color;
 
845
  // No color names begin with a '#', but numerical colors do so
 
846
  // it is a very common first char
 
847
  if ((colorStr.CharAt(0) != '#') && NS_ColorNameToRGB(colorStr, &color)) {
 
848
    SetTo(colorStr);
 
849
    return PR_TRUE;
 
850
  }
 
851
 
 
852
  // Check if we are in compatibility mode
 
853
  // XXX evil NS_HexToRGB and NS_LooseHexToRGB take nsString as argument!
 
854
  nsCOMPtr<nsIHTMLDocument> doc(do_QueryInterface(aDocument));
 
855
  if (doc && doc->GetCompatibilityMode() == eCompatibility_NavQuirks) {
 
856
    NS_LooseHexToRGB(colorStr, &color);
 
857
  }
 
858
  else {
 
859
    if (colorStr.First() != '#') {
 
860
      Reset();
 
861
      return PR_FALSE;
 
862
    }
 
863
    colorStr.Cut(0, 1);
 
864
    if (!NS_HexToRGB(colorStr, &color)) {
 
865
      Reset();
 
866
      return PR_FALSE;
 
867
    }
 
868
  }
 
869
 
 
870
  PRInt32 colAsInt = NS_STATIC_CAST(PRInt32, color);
 
871
  PRInt32 tmp = colAsInt * NS_ATTRVALUE_INTEGERTYPE_MULTIPLIER;
 
872
  if (tmp / NS_ATTRVALUE_INTEGERTYPE_MULTIPLIER == colAsInt) {
 
873
    ResetIfSet();
 
874
    SetIntValueAndType(colAsInt, eColor);
 
875
  }
 
876
  else if (EnsureEmptyMiscContainer()) {
 
877
    MiscContainer* cont = GetMiscContainer();
 
878
    cont->mColor = color;
 
879
    cont->mType = eColor;
 
880
  }
 
881
 
 
882
  return PR_TRUE;
 
883
}
 
884
 
 
885
PRBool
 
886
nsAttrValue::EnsureEmptyMiscContainer()
 
887
{
 
888
  MiscContainer* cont;
 
889
  if (BaseType() == eOtherBase) {
 
890
    cont = GetMiscContainer();
 
891
    switch (cont->mType) {
 
892
      case eCSSStyleRule:
 
893
      {
 
894
        NS_RELEASE(cont->mCSSStyleRule);
 
895
        break;
 
896
      }
 
897
      case eAtomArray:
 
898
      {
 
899
        delete cont->mAtomArray;
 
900
        break;
 
901
      }
 
902
      default:
 
903
      {
 
904
        break;
 
905
      }
 
906
    }
 
907
  }
 
908
  else {
 
909
    ResetIfSet();
 
910
 
 
911
    cont = new MiscContainer;
 
912
    NS_ENSURE_TRUE(cont, PR_FALSE);
 
913
 
 
914
    SetPtrValueAndType(cont, eOtherBase);
 
915
  }
 
916
 
 
917
  cont->mType = eColor;
 
918
  cont->mColor = 0;
 
919
 
 
920
  return PR_TRUE;
 
921
}
 
922
 
 
923
PRBool
 
924
nsAttrValue::EnsureEmptyAtomArray()
 
925
{
 
926
  if (Type() == eAtomArray) {
 
927
    GetAtomArrayValue()->Clear();
 
928
    return PR_TRUE;
 
929
  }
 
930
 
 
931
  if (!EnsureEmptyMiscContainer()) {
 
932
    // should already be reset
 
933
    return PR_FALSE;
 
934
  }
 
935
 
 
936
  nsCOMArray<nsIAtom>* array = new nsCOMArray<nsIAtom>;
 
937
  if (!array) {
 
938
    Reset();
 
939
    return PR_FALSE;
 
940
  }
 
941
 
 
942
  MiscContainer* cont = GetMiscContainer();
 
943
  cont->mAtomArray = array;
 
944
  cont->mType = eAtomArray;
 
945
 
 
946
  return PR_TRUE;
 
947
}