Bug 543151, part A2: Introduce the new peek/advance API and reimplement the old read/pushback API on top of it. r=heycam
authorZack Weinberg <zackw@panix.com>
Sat, 16 Feb 2013 18:27:53 -0500
changeset 132815 68c9f2677339f5a238a08af93c80f9afd2cf0f77
parent 132814 a94f2ab8ddf94486b724578854d02161c83ade23
child 132816 a0a8c0ed0c77d9e5db93d16897be1d26fc7744eb
push id317
push userbbajaj@mozilla.com
push dateTue, 07 May 2013 01:20:33 +0000
treeherdermozilla-release@159a10910249 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersheycam
bugs543151
milestone21.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 543151, part A2: Introduce the new peek/advance API and reimplement the old read/pushback API on top of it. r=heycam
layout/style/nsCSSParser.cpp
layout/style/nsCSSScanner.cpp
layout/style/nsCSSScanner.h
layout/style/test/test_bug413958.html
--- a/layout/style/nsCSSParser.cpp
+++ b/layout/style/nsCSSParser.cpp
@@ -3796,19 +3796,17 @@ CSSParserImpl::ParsePseudoClassWithNthPa
     // minus on back onto the scanner's pushback buffer.
     uint32_t truncAt = 0;
     if (StringBeginsWith(mToken.mIdent, NS_LITERAL_STRING("n-"))) {
       truncAt = 1;
     } else if (StringBeginsWith(mToken.mIdent, NS_LITERAL_STRING("-n-"))) {
       truncAt = 2;
     }
     if (truncAt != 0) {
-      for (uint32_t i = mToken.mIdent.Length() - 1; i >= truncAt; --i) {
-        mScanner->Pushback(mToken.mIdent[i]);
-      }
+      mScanner->Backup(mToken.mIdent.Length() - truncAt);
       mToken.mIdent.Truncate(truncAt);
     }
   }
 
   if (eCSSToken_Ident == mToken.mType) {
     if (mToken.mIdent.LowerCaseEqualsLiteral("odd")) {
       numbers[0] = 2;
       numbers[1] = 1;
--- a/layout/style/nsCSSScanner.cpp
+++ b/layout/style/nsCSSScanner.cpp
@@ -13,100 +13,112 @@
 #include "mozilla/css/ErrorReporter.h"
 #include "mozilla/Likely.h"
 #include "mozilla/Util.h"
 #include <algorithm>
 
 using mozilla::ArrayLength;
 
 static const uint8_t IS_HEX_DIGIT  = 0x01;
-static const uint8_t START_IDENT   = 0x02;
-static const uint8_t IS_IDENT      = 0x04;
-static const uint8_t IS_WHITESPACE = 0x08;
-static const uint8_t IS_URL_CHAR   = 0x10;
+static const uint8_t IS_IDSTART    = 0x02;
+static const uint8_t IS_IDCHAR     = 0x04;
+static const uint8_t IS_URL_CHAR   = 0x08;
+static const uint8_t IS_HSPACE     = 0x10;
+static const uint8_t IS_VSPACE     = 0x20;
+static const uint8_t IS_SPACE      = IS_HSPACE|IS_VSPACE;
 
-#define W    IS_WHITESPACE
-#define I    IS_IDENT
+#define H    IS_HSPACE
+#define V    IS_VSPACE
+#define I    IS_IDCHAR
 #define U                                      IS_URL_CHAR
-#define S             START_IDENT
-#define UI   IS_IDENT                         |IS_URL_CHAR
-#define USI  IS_IDENT|START_IDENT             |IS_URL_CHAR
-#define UXI  IS_IDENT            |IS_HEX_DIGIT|IS_URL_CHAR
-#define UXSI IS_IDENT|START_IDENT|IS_HEX_DIGIT|IS_URL_CHAR
+#define S              IS_IDSTART
+#define UI   IS_IDCHAR                        |IS_URL_CHAR
+#define USI  IS_IDCHAR|IS_IDSTART             |IS_URL_CHAR
+#define UXI  IS_IDCHAR           |IS_HEX_DIGIT|IS_URL_CHAR
+#define UXSI IS_IDCHAR|IS_IDSTART|IS_HEX_DIGIT|IS_URL_CHAR
 
 static const uint8_t gLexTable[] = {
 //                                     TAB LF      FF  CR
-   0,  0,  0,  0,  0,  0,  0,  0,  0,  W,  W,  0,  W,  W,  0,  0,
+   0,  0,  0,  0,  0,  0,  0,  0,  0,  H,  V,  0,  V,  V,  0,  0,
 //
    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
 // SPC !   "   #   $   %   &   '   (   )   *   +   ,   -   .   /
-   W,  U,  0,  U,  U,  U,  U,  0,  0,  0,  U,  U,  U,  UI, U,  U,
+   H,  U,  0,  U,  U,  U,  U,  0,  0,  0,  U,  U,  U,  UI, U,  U,
 // 0   1   2   3   4   5   6   7   8   9   :   ;   <   =   >   ?
    UXI,UXI,UXI,UXI,UXI,UXI,UXI,UXI,UXI,UXI,U,  U,  U,  U,  U,  U,
 // @   A   B   C    D    E    F    G   H   I   J   K   L   M   N   O
    U,UXSI,UXSI,UXSI,UXSI,UXSI,UXSI,USI,USI,USI,USI,USI,USI,USI,USI,USI,
 // P   Q   R   S   T   U   V   W   X   Y   Z   [   \   ]   ^   _
    USI,USI,USI,USI,USI,USI,USI,USI,USI,USI,USI,U,  S,  U,  U,  USI,
 // `   a   b   c    d    e    f    g   h   i   j   k   l   m   n   o
    U,UXSI,UXSI,UXSI,UXSI,UXSI,UXSI,USI,USI,USI,USI,USI,USI,USI,USI,USI,
 // p   q   r   s   t   u   v   w   x   y   z   {   |   }   ~
    USI,USI,USI,USI,USI,USI,USI,USI,USI,USI,USI,U,  U,  U,  U,  0
 };
 
-MOZ_STATIC_ASSERT(NS_ARRAY_LENGTH(gLexTable) == 128,
+MOZ_STATIC_ASSERT(MOZ_ARRAY_LENGTH(gLexTable) == 128,
                   "gLexTable expected to cover all 128 ASCII characters");
 
-#undef W
+#undef H
+#undef V
 #undef S
 #undef I
 #undef U
 #undef UI
 #undef USI
 #undef UXI
 #undef UXSI
 
 static inline bool
-IsIdentStart(int32_t aChar)
-{
-  return aChar >= 0 &&
-    (aChar >= 128 || (gLexTable[aChar] & START_IDENT) != 0);
+IsHorzSpace(int32_t ch) {
+  return uint32_t(ch) < 128 && (gLexTable[ch] & IS_HSPACE) != 0;
+}
+
+static inline bool
+IsVertSpace(int32_t ch) {
+  return uint32_t(ch) < 128 && (gLexTable[ch] & IS_VSPACE) != 0;
+}
+
+static inline bool
+IsWhitespace(int32_t ch) {
+  return uint32_t(ch) < 128 && (gLexTable[ch] & IS_SPACE) != 0;
+}
+
+static inline bool
+IsIdentChar(int32_t ch) {
+  return ch >= 0 && (ch >= 128 || (gLexTable[ch] & IS_IDCHAR) != 0);
+}
+
+static inline bool
+IsIdentStart(int32_t ch) {
+  return ch >= 0 && (ch >= 128 || (gLexTable[ch] & IS_IDSTART) != 0);
 }
 
 static inline bool
 StartsIdent(int32_t aFirstChar, int32_t aSecondChar)
 {
   return IsIdentStart(aFirstChar) ||
     (aFirstChar == '-' && IsIdentStart(aSecondChar));
 }
 
 static inline bool
-IsWhitespace(int32_t ch) {
-  return uint32_t(ch) < 128 && (gLexTable[ch] & IS_WHITESPACE) != 0;
+IsURLChar(int32_t ch) {
+  return ch >= 0 && (ch >= 128 || (gLexTable[ch] & IS_URL_CHAR) != 0);
 }
 
 static inline bool
 IsDigit(int32_t ch) {
   return (ch >= '0') && (ch <= '9');
 }
 
 static inline bool
 IsHexDigit(int32_t ch) {
   return uint32_t(ch) < 128 && (gLexTable[ch] & IS_HEX_DIGIT) != 0;
 }
 
-static inline bool
-IsIdent(int32_t ch) {
-  return ch >= 0 && (ch >= 128 || (gLexTable[ch] & IS_IDENT) != 0);
-}
-
-static inline bool
-IsURLChar(int32_t ch) {
-  return ch >= 0 && (ch >= 128 || (gLexTable[ch] & IS_URL_CHAR) != 0);
-}
-
 static inline uint32_t
 DecimalDigitValue(int32_t ch)
 {
   return ch - '0';
 }
 
 static inline uint32_t
 HexDigitValue(int32_t ch)
@@ -225,198 +237,264 @@ nsCSSToken::AppendToString(nsString& aBu
       break;
   }
 }
 
 nsCSSScanner::nsCSSScanner(const nsAString& aBuffer, uint32_t aLineNumber)
   : mBuffer(aBuffer.BeginReading())
   , mOffset(0)
   , mCount(aBuffer.Length())
-  , mPushback(mLocalPushback)
-  , mPushbackCount(0)
-  , mPushbackSize(ArrayLength(mLocalPushback))
   , mLineNumber(aLineNumber)
   , mLineOffset(0)
   , mTokenLineNumber(aLineNumber)
   , mTokenLineOffset(0)
   , mTokenOffset(0)
   , mRecordStartOffset(0)
   , mReporter(nullptr)
   , mSVGMode(false)
   , mRecording(false)
 {
   MOZ_COUNT_CTOR(nsCSSScanner);
 }
 
 nsCSSScanner::~nsCSSScanner()
 {
   MOZ_COUNT_DTOR(nsCSSScanner);
-  if (mLocalPushback != mPushback) {
-    delete [] mPushback;
-  }
 }
 
 void
 nsCSSScanner::StartRecording()
 {
-  NS_ASSERTION(!mRecording, "already started recording");
+  MOZ_ASSERT(!mRecording, "already started recording");
   mRecording = true;
-  mRecordStartOffset = mOffset - mPushbackCount;
+  mRecordStartOffset = mOffset;
 }
 
 void
 nsCSSScanner::StopRecording()
 {
-  NS_ASSERTION(mRecording, "haven't started recording");
+  MOZ_ASSERT(mRecording, "haven't started recording");
   mRecording = false;
 }
 
 void
 nsCSSScanner::StopRecording(nsString& aBuffer)
 {
-  NS_ASSERTION(mRecording, "haven't started recording");
+  MOZ_ASSERT(mRecording, "haven't started recording");
   mRecording = false;
   aBuffer.Append(mBuffer + mRecordStartOffset,
-                 mOffset - mPushbackCount - mRecordStartOffset);
+                 mOffset - mRecordStartOffset);
 }
 
 nsDependentSubstring
 nsCSSScanner::GetCurrentLine() const
 {
   uint32_t end = mTokenOffset;
-  while (end < mCount &&
-         mBuffer[end] != '\n' && mBuffer[end] != '\r' &&
-         mBuffer[end] != '\f') {
+  while (end < mCount && !IsVertSpace(mBuffer[end])) {
     end++;
   }
   return nsDependentSubstring(mBuffer + mTokenLineOffset,
                               mBuffer + end);
 }
 
+/**
+ * Return the raw UTF-16 code unit at position |mOffset + n| within
+ * the read buffer.  If that is beyond the end of the buffer, returns
+ * -1 to indicate end of input.
+ */
+inline int32_t
+nsCSSScanner::Peek(uint32_t n)
+{
+  if (mOffset + n >= mCount) {
+    return -1;
+  }
+  return mBuffer[mOffset + n];
+}
+
+/**
+ * Advance |mOffset| over |n| code units.  Advance(0) is a no-op.
+ * If |n| is greater than the distance to end of input, will silently
+ * stop at the end.  May not be used to advance over a line boundary;
+ * AdvanceLine() must be used instead.
+ */
+inline void
+nsCSSScanner::Advance(uint32_t n)
+{
+#ifdef DEBUG
+  while (mOffset < mCount && n > 0) {
+    MOZ_ASSERT(!IsVertSpace(mBuffer[mOffset]),
+               "may not Advance() over a line boundary");
+    mOffset++;
+    n--;
+  }
+#else
+  if (mOffset + n >= mCount || mOffset + n < mOffset)
+    mOffset = mCount;
+  else
+    mOffset += n;
+#endif
+}
+
+/**
+ * Advance |mOffset| over a line boundary.
+ */
+void
+nsCSSScanner::AdvanceLine()
+{
+  MOZ_ASSERT(IsVertSpace(mBuffer[mOffset]),
+             "may not AdvanceLine() over a horizontal character");
+  // Advance over \r\n as a unit.
+  if (mBuffer[mOffset]   == '\r' && mOffset + 1 < mCount &&
+      mBuffer[mOffset+1] == '\n')
+    mOffset += 2;
+  else
+    mOffset += 1;
+  // 0 is a magical line number meaning that we don't know (i.e., script)
+  if (mLineNumber != 0)
+    mLineNumber++;
+  mLineOffset = mOffset;
+}
+
+/**
+ * Back up |mOffset| over |n| code units.  Backup(0) is a no-op.
+ * If |n| is greater than the distance to beginning of input, will
+ * silently stop at the beginning.  May not be used to back up over a
+ * line boundary.
+ */
+void
+nsCSSScanner::Backup(uint32_t n)
+{
+#if 1
+  // Right now, code below does occasionally need to back up over a
+  // line boundary.  This will cease to be required later in this
+  // patch series.  Note that we do not attempt to correct mLineOffset.
+  while (mOffset > 0 && n > 0) {
+    if (IsVertSpace(mBuffer[mOffset-1])) {
+      if (mBuffer[mOffset-1] == '\n' && mOffset > 1 &&
+          mBuffer[mOffset-2] == '\r') {
+        mOffset -= 2;
+      } else {
+        mOffset -= 1;
+      }
+      n--;
+      mLineNumber--;
+    } else {
+      mOffset--;
+      n--;
+    }
+  }
+#else
+#ifdef DEBUG
+  while (mOffset > 0 && n > 0) {
+    MOZ_ASSERT(!IsVertSpace(mBuffer[mOffset-1]),
+               "may not Backup() over a line boundary");
+    mOffset--;
+    n--;
+  }
+#else
+  if (mOffset < n)
+    mOffset = 0;
+  else
+    mOffset -= n;
+#endif
+#endif
+}
+
 // Returns -1 on error or eof
 int32_t
 nsCSSScanner::Read()
 {
-  int32_t rv;
-  if (0 < mPushbackCount) {
-    rv = int32_t(mPushback[--mPushbackCount]);
-  } else {
-    if (mOffset == mCount) {
-      return -1;
-    }
-    rv = int32_t(mBuffer[mOffset++]);
-    // There are four types of newlines in CSS: "\r", "\n", "\r\n", and "\f".
-    // To simplify dealing with newlines, they are all normalized to "\n" here
-    if (rv == '\r') {
-      if (mOffset < mCount && mBuffer[mOffset] == '\n') {
-        mOffset++;
-      }
-      rv = '\n';
-    } else if (rv == '\f') {
-      rv = '\n';
-    }
-    if (rv == '\n') {
-      // 0 is a magical line number meaning that we don't know (i.e., script)
-      if (mLineNumber != 0)
-        ++mLineNumber;
-      mLineOffset = mOffset;
-    }
+  int32_t rv = Peek();
+
+  // There are four types of newlines in CSS: "\r", "\n", "\r\n", and "\f".
+  // To simplify dealing with newlines, they are all normalized to "\n" here.
+  if (IsVertSpace(rv)) {
+    AdvanceLine();
+    rv = '\n';
+  } else if (rv >= 0) {
+    Advance();
   }
   return rv;
 }
 
-int32_t
-nsCSSScanner::Peek()
-{
-  if (0 == mPushbackCount) {
-    int32_t ch = Read();
-    if (ch < 0) {
-      return -1;
-    }
-    mPushback[0] = PRUnichar(ch);
-    mPushbackCount++;
-  }
-  return int32_t(mPushback[mPushbackCount - 1]);
-}
-
 void
 nsCSSScanner::Pushback(PRUnichar aChar)
 {
-  if (mPushbackCount == mPushbackSize) { // grow buffer
-    PRUnichar*  newPushback = new PRUnichar[mPushbackSize + 4];
-    if (nullptr == newPushback) {
-      return;
-    }
-    mPushbackSize += 4;
-    memcpy(newPushback, mPushback, sizeof(PRUnichar) * mPushbackCount);
-    if (mPushback != mLocalPushback) {
-      delete [] mPushback;
-    }
-    mPushback = newPushback;
-  }
-  mPushback[mPushbackCount++] = aChar;
+  MOZ_ASSERT(mOffset > 0 && aChar == mBuffer[mOffset-1],
+             "may only push back exactly what was read");
+  Backup(1);
 }
 
 bool
 nsCSSScanner::LookAhead(PRUnichar aChar)
 {
-  int32_t ch = Read();
-  if (ch < 0) {
-    return false;
-  }
-  if (ch == aChar) {
+  if (Peek() == aChar) {
+    if (IsVertSpace(aChar)) {
+      AdvanceLine();
+    } else {
+      Advance();
+    }
     return true;
   }
-  Pushback(ch);
   return false;
 }
 
 bool
 nsCSSScanner::LookAheadOrEOF(PRUnichar aChar)
 {
-  int32_t ch = Read();
-  if (ch < 0) {
+  int32_t ch = Peek();
+  if (ch == -1) {
     return true;
   }
   if (ch == aChar) {
+    if (IsVertSpace(aChar)) {
+      AdvanceLine();
+    } else {
+      Advance();
+    }
     return true;
   }
-  Pushback(ch);
   return false;
 }
 
 void
 nsCSSScanner::SkipWhitespace()
 {
   for (;;) {
-    int32_t ch = Read();
-    if (ch < 0) {
+    int32_t ch = Peek();
+    if (!IsWhitespace(ch)) { // EOF counts as non-whitespace
       break;
     }
-    if ((ch != ' ') && (ch != '\n') && (ch != '\t')) {
-      Pushback(ch);
-      break;
+    if (IsVertSpace(ch)) {
+      AdvanceLine();
+    } else {
+      Advance();
     }
   }
 }
 
 void
 nsCSSScanner::SkipComment()
 {
   for (;;) {
-    int32_t ch = Read();
-    if (ch < 0) break;
-    if (ch == '*') {
-      if (LookAhead('/')) {
-        return;
-      }
+    int32_t ch = Peek();
+    if (ch < 0) {
+      mReporter->ReportUnexpectedEOF("PECommentEOF");
+      return;
+    }
+    if (ch == '*' && Peek(1) == '/') {
+      Advance(2);
+      return;
+    }
+    if (IsVertSpace(ch)) {
+      AdvanceLine();
+    } else {
+      Advance();
     }
   }
-
-  mReporter->ReportUnexpectedEOF("PECommentEOF");
 }
 
 /**
  * Returns whether an escape was succesfully parsed; if it was not,
  * the backslash needs to be its own symbol token.
  */
 bool
 nsCSSScanner::GatherEscape(nsString& aOutput, bool aInString)
@@ -510,39 +588,38 @@ nsCSSScanner::GatherIdent(int32_t aChar,
     if (!GatherEscape(aIdent, false)) {
       return false;
     }
   } else {
     MOZ_ASSERT(aChar > 0);
     aIdent.Append(aChar);
   }
   for (;;) {
-    // If nothing in pushback, first try to get as much as possible in one go
-    if (!mPushbackCount && mOffset < mCount) {
+    if (mOffset < mCount) {
       // See how much we can consume and append in one go
       uint32_t n = mOffset;
       // Count number of Ident characters that can be processed
-      while (n < mCount && IsIdent(mBuffer[n])) {
+      while (n < mCount && IsIdentChar(mBuffer[n])) {
         ++n;
       }
       // Add to the token what we have so far
       if (n > mOffset) {
         aIdent.Append(&mBuffer[mOffset], n - mOffset);
         mOffset = n;
       }
     }
 
     aChar = Read();
     if (aChar < 0) break;
     if (aChar == '\\') {
       if (!GatherEscape(aIdent, false)) {
         Pushback(aChar);
         break;
       }
-    } else if (IsIdent(aChar)) {
+    } else if (IsIdentChar(aChar)) {
       aIdent.Append(PRUnichar(aChar));
     } else {
       Pushback(aChar);
       break;
     }
   }
   MOZ_ASSERT(aIdent.Length() > 0);
   return true;
@@ -600,17 +677,17 @@ nsCSSScanner::ScanHash(int32_t aChar, ns
   // Fall back for when we don't have name characters following:
   aToken.mType = eCSSToken_Symbol;
   aToken.mSymbol = aChar;
 
   int32_t ch = Read();
   if (ch < 0) {
     return true;
   }
-  if (IsIdent(ch) || ch == '\\') {
+  if (IsIdentChar(ch) || ch == '\\') {
     // First char after the '#' is a valid ident char (or an escape),
     // so it makes sense to keep going
     nsCSSTokenType type =
       StartsIdent(ch, Peek()) ? eCSSToken_ID : eCSSToken_Hash;
     aToken.mIdent.SetLength(0);
     if (GatherIdent(ch, aToken.mIdent)) {
       aToken.mType = type;
       return true;
@@ -758,18 +835,17 @@ nsCSSScanner::ScanNumber(int32_t c, nsCS
 
 bool
 nsCSSScanner::ScanString(int32_t aStop, nsCSSToken& aToken)
 {
   aToken.mIdent.SetLength(0);
   aToken.mType = eCSSToken_String;
   aToken.mSymbol = PRUnichar(aStop); // remember how it's quoted
   for (;;) {
-    // If nothing in pushback, first try to get as much as possible in one go
-    if (!mPushbackCount && mOffset < mCount) {
+    if (mOffset < mCount) {
       // See how much we can consume and append in one go
       uint32_t n = mOffset;
       // Count number of characters that can be processed
       for (;n < mCount; ++n) {
         PRUnichar nextChar = mBuffer[n];
         if ((nextChar == aStop) || (nextChar == '\\') ||
             (nextChar == '\n') || (nextChar == '\r') || (nextChar == '\f')) {
           break;
--- a/layout/style/nsCSSScanner.h
+++ b/layout/style/nsCSSScanner.h
@@ -166,31 +166,37 @@ class nsCSSScanner {
   // parser.
   bool NextURL(nsCSSToken& aTokenResult);
 
   // This is exposed for use by nsCSSParser::ParsePseudoClassWithNthPairArg,
   // because "2n-1" is a single DIMENSION token, and "n-1" is a single
   // IDENT token, but the :nth() selector syntax wants to interpret
   // them the same as "2n -1" and "n -1" respectively.  Please do not
   // add new uses to the parser.
-  void Pushback(PRUnichar aChar);
+  //
+  // Note: this function may not be used to back up over a line boundary.
+  void Backup(uint32_t n);
 
   // Starts recording the input stream from the current position.
   void StartRecording();
 
   // Abandons recording of the input stream.
   void StopRecording();
 
   // Stops recording of the input stream and appends the recorded
   // input to aBuffer.
   void StopRecording(nsString& aBuffer);
 
 protected:
+  int32_t Peek(uint32_t n = 0);
+  void Advance(uint32_t n = 1);
+  void AdvanceLine();
+
   int32_t Read();
-  int32_t Peek();
+  void Pushback(PRUnichar aChar);
   bool LookAhead(PRUnichar aChar);
   bool LookAheadOrEOF(PRUnichar aChar); // expect either aChar or EOF
 
   void SkipWhitespace();
   void SkipComment();
 
   bool GatherEscape(nsString& aOutput, bool aInString);
   bool GatherIdent(int32_t aChar, nsString& aIdent);
@@ -201,21 +207,16 @@ protected:
   bool ScanNumber(int32_t aChar, nsCSSToken& aResult);
   bool ScanString(int32_t aChar, nsCSSToken& aResult);
   bool ScanURange(int32_t aChar, nsCSSToken& aResult);
 
   const PRUnichar *mBuffer;
   uint32_t mOffset;
   uint32_t mCount;
 
-  PRUnichar* mPushback;
-  int32_t mPushbackCount;
-  int32_t mPushbackSize;
-  PRUnichar mLocalPushback[4];
-
   uint32_t mLineNumber;
   uint32_t mLineOffset;
 
   uint32_t mTokenLineNumber;
   uint32_t mTokenLineOffset;
   uint32_t mTokenOffset;
 
   uint32_t mRecordStartOffset;
--- a/layout/style/test/test_bug413958.html
+++ b/layout/style/test/test_bug413958.html
@@ -36,26 +36,26 @@ var tests = [
   function() {
     var s = document.getElementById("setStyleProp").style;
     s.width = "200";
     s.color = "black";
   },
 ];
 var results = [
   [ { errorMessage: /Unknown property 'nosuchprop'/,
-      lineNumber: 1, columnNumber: 15,
+      lineNumber: 1, columnNumber: 14,
       sourceLine: "#s1{nosuchprop:auto; color:black}" },
     { errorMessage: /Unknown property 'nosuchprop'/,
-      lineNumber: 2, columnNumber: 15, sourceLine:
+      lineNumber: 2, columnNumber: 14, sourceLine:
       "#s2{nosuchprop:auto; color:black}invalid?sel{}#s3{color:black}" },
     { errorMessage: /Ruleset ignored due to bad selector/,
-      lineNumber: 2, columnNumber: 41, sourceLine:
+      lineNumber: 2, columnNumber: 40, sourceLine:
       "#s2{nosuchprop:auto; color:black}invalid?sel{}#s3{color:black}" } ],
   [ { errorMessage: /parsing value for 'width'/,
-      lineNumber: 0, columnNumber: 7,
+      lineNumber: 0, columnNumber: 6,
       sourceLine: "width:200;color:black" } ],
   [ { errorMessage: /parsing value for 'width'/,
       lineNumber: 0, columnNumber: 0,
       sourceLine: "200" } ],
 ];
 var curTest = -1;
 
 function doTest() {