// http://www.w3.org/TR/css3-syntax/#consume-a-name CSSParserString CSSTokenizer::consumeName() { // Names without escapes get handled without allocations for (unsigned size = 0; ; ++size) { UChar cc = m_input.peekWithoutReplacement(size); if (cc == '\0' || cc == '\\') break; if (!isNameChar(cc)) { unsigned startOffset = m_input.offset(); m_input.advance(size); return m_input.rangeAsCSSParserString(startOffset, size); } } StringBuilder result; while (true) { UChar cc = consume(); if (isNameChar(cc)) { result.append(cc); continue; } if (twoCharsAreValidEscape(cc, m_input.nextInputChar())) { result.append(consumeEscape()); continue; } reconsume(cc); return registerString(result.toString()); } }
CSSParserToken CSSTokenizer::reverseSolidus(UChar cc) { if (twoCharsAreValidEscape(cc, m_input.nextInputChar())) { reconsume(cc); return consumeIdentLikeToken(); } return CSSParserToken(DelimiterToken, cc); }
// http://dev.w3.org/csswg/css-syntax/#consume-the-remnants-of-a-bad-url void CSSTokenizer::consumeBadUrlRemnants() { while (true) { UChar cc = consume(); if (cc == ')' || cc == kEndOfFileMarker) return; if (twoCharsAreValidEscape(cc, m_input.nextInputChar())) consumeEscape(); } }
CSSParserToken CSSTokenizer::hash(UChar cc) { UChar nextChar = m_input.nextInputChar(); if (isNameChar(nextChar) || twoCharsAreValidEscape(nextChar, m_input.peek(1))) { HashTokenType type = nextCharsAreIdentifier() ? HashTokenId : HashTokenUnrestricted; return CSSParserToken(type, consumeName()); } return CSSParserToken(DelimiterToken, cc); }
// http://dev.w3.org/csswg/css-syntax/#would-start-an-identifier bool CSSTokenizer::nextCharsAreIdentifier(UChar first) { UChar second = m_input.nextInputChar(); if (isNameStart(first) || twoCharsAreValidEscape(first, second)) return true; if (first == '-') return isNameStart(second) || second == '-' || nextTwoCharsAreValidEscape(); return false; }
// http://www.w3.org/TR/css3-syntax/#would-start-an-identifier bool MediaQueryTokenizer::nextCharsAreIdentifier(UChar first) { UChar second = m_input.nextInputChar(); if (isNameStart(first) || twoCharsAreValidEscape(first, second)) return true; if (first == '-') { if (isNameStart(m_input.nextInputChar())) return true; return nextTwoCharsAreValidEscape(); } return false; }
// http://dev.w3.org/csswg/css-syntax/#consume-url-token CSSParserToken CSSTokenizer::consumeUrlToken() { consumeUntilNonWhitespace(); // URL tokens without escapes get handled without allocations for (unsigned size = 0; ; size++) { UChar cc = m_input.peekWithoutReplacement(size); if (cc == ')') { unsigned startOffset = m_input.offset(); m_input.advance(size + 1); return CSSParserToken(UrlToken, m_input.rangeAsCSSParserString(startOffset, size)); } if (cc <= ' ' || cc == '\\' || cc == '"' || cc == '\'' || cc == '(' || cc == '\x7f') break; } StringBuilder result; while (true) { UChar cc = consume(); if (cc == ')' || cc == kEndOfFileMarker) return CSSParserToken(UrlToken, registerString(result.toString())); if (isHTMLSpace(cc)) { consumeUntilNonWhitespace(); if (consumeIfNext(')') || m_input.nextInputChar() == kEndOfFileMarker) return CSSParserToken(UrlToken, registerString(result.toString())); break; } if (cc == '"' || cc == '\'' || cc == '(' || isNonPrintableCodePoint(cc)) break; if (cc == '\\') { if (twoCharsAreValidEscape(cc, m_input.nextInputChar())) { result.append(consumeEscape()); continue; } break; } result.append(cc); } consumeBadUrlRemnants(); return CSSParserToken(BadUrlToken); }
// http://www.w3.org/TR/css3-syntax/#consume-a-name String MediaQueryTokenizer::consumeName() { // FIXME: Is this as efficient as it can be? // The possibility of escape chars mandates a copy AFAICT. StringBuilder result; while (true) { UChar cc = consume(); if (isNameChar(cc)) { result.append(cc); continue; } if (twoCharsAreValidEscape(cc, m_input.nextInputChar())) { result.append(consumeEscape()); continue; } reconsume(cc); return result.toString(); } }
// http://dev.w3.org/csswg/css-syntax/#consume-url-token CSSParserToken CSSTokenizer::consumeUrlToken() { consumeUntilNonWhitespace(); StringBuilder result; while (true) { UChar cc = consume(); if (cc == ')' || cc == kEndOfFileMarker) { // The "reconsume" here deviates from the spec, but is required to avoid consuming past the EOF if (cc == kEndOfFileMarker) reconsume(cc); return CSSParserToken(UrlToken, result.toString()); } if (isHTMLSpace(cc)) { consumeUntilNonWhitespace(); if (consumeIfNext(')') || m_input.nextInputChar() == kEndOfFileMarker) return CSSParserToken(UrlToken, result.toString()); break; } if (cc == '"' || cc == '\'' || cc == '(' || isNonPrintableCodePoint(cc)) break; if (cc == '\\') { if (twoCharsAreValidEscape(cc, m_input.nextInputChar())) { result.append(consumeEscape()); continue; } break; } result.append(cc); } consumeBadUrlRemnants(); return CSSParserToken(BadUrlToken); }
bool CSSTokenizer::nextTwoCharsAreValidEscape() { return twoCharsAreValidEscape(m_input.nextInputChar(), m_input.peek(1)); }
bool MediaQueryTokenizer::nextTwoCharsAreValidEscape() { if (m_input.leftChars() < 1) return false; return twoCharsAreValidEscape(m_input.nextInputChar(), m_input.peek(1)); }