Beispiel #1
0
bool SelectorChecker::checkOne(const SelectorCheckingContext& context) const
{
    Element* const & element = context.element;
    const CSSSelector* const & selector = context.selector;
    ASSERT(element);
    ASSERT(selector);

    if (selector->m_match == CSSSelector::Tag)
        return SelectorChecker::tagMatches(element, selector->tagQName());

    if (selector->m_match == CSSSelector::Class)
        return element->hasClass() && element->classNames().contains(selector->value());

    if (selector->m_match == CSSSelector::Id)
        return element->hasID() && element->idForStyleResolution() == selector->value();

    if (selector->isAttributeSelector()) {
        const QualifiedName& attr = selector->attribute();

        if (!element->hasAttributes())
            return false;

        bool caseSensitive = !m_documentIsHTML || HTMLDocument::isCaseSensitiveAttribute(attr);

        if (!anyAttributeMatches(element, static_cast<CSSSelector::Match>(selector->m_match), attr, selector->value(), caseSensitive))
            return false;
    }

    if (selector->m_match == CSSSelector::PseudoClass) {
        // Handle :not up front.
        if (selector->pseudoType() == CSSSelector::PseudoNot) {
            const CSSSelectorList* selectorList = selector->selectorList();

            // FIXME: We probably should fix the parser and make it never produce :not rules with missing selector list.
            if (!selectorList)
                return false;

            SelectorCheckingContext subContext(context);
            subContext.isSubSelector = true;
            for (subContext.selector = selectorList->first(); subContext.selector; subContext.selector = subContext.selector->tagHistory()) {
                // :not cannot nest. I don't really know why this is a
                // restriction in CSS3, but it is, so let's honor it.
                // the parser enforces that this never occurs
                ASSERT(subContext.selector->pseudoType() != CSSSelector::PseudoNot);
                // We select between :visited and :link when applying. We don't know which one applied (or not) yet.
                if (subContext.selector->pseudoType() == CSSSelector::PseudoVisited || (subContext.selector->pseudoType() == CSSSelector::PseudoLink && subContext.visitedMatchType == VisitedMatchEnabled))
                    return true;
                if (!checkOne(subContext))
                    return true;
            }
        } else if (context.hasScrollbarPseudo) {
            // CSS scrollbars match a specific subset of pseudo classes, and they have specialized rules for each
            // (since there are no elements involved).
            return checkScrollbarPseudoClass(context, element->document(), selector);
        } else if (context.hasSelectionPseudo) {
            if (selector->pseudoType() == CSSSelector::PseudoWindowInactive)
                return !element->document()->page()->focusController()->isActive();
        }

        // Normal element pseudo class checking.
        switch (selector->pseudoType()) {
            // Pseudo classes:
        case CSSSelector::PseudoNot:
            break; // Already handled up above.
        case CSSSelector::PseudoEmpty:
            {
                bool result = true;
                for (Node* n = element->firstChild(); n; n = n->nextSibling()) {
                    if (n->isElementNode()) {
                        result = false;
                        break;
                    }
                    if (n->isTextNode()) {
                        Text* textNode = toText(n);
                        if (!textNode->data().isEmpty()) {
                            result = false;
                            break;
                        }
                    }
                }
                if (m_mode == ResolvingStyle) {
                    element->setStyleAffectedByEmpty();
                    if (context.elementStyle)
                        context.elementStyle->setEmptyState(result);
                    else if (element->renderStyle() && (element->document()->styleSheetCollection()->usesSiblingRules() || element->renderStyle()->unique()))
                        element->renderStyle()->setEmptyState(result);
                }
                return result;
            }
        case CSSSelector::PseudoFirstChild:
            // first-child matches the first child that is an element
            if (Element* parentElement = element->parentElement()) {
                bool result = isFirstChildElement(element);
                if (m_mode == ResolvingStyle) {
                    RenderStyle* childStyle = context.elementStyle ? context.elementStyle : element->renderStyle();
                    parentElement->setChildrenAffectedByFirstChildRules();
                    if (result && childStyle)
                        childStyle->setFirstChildState();
                }
                return result;
            }
            break;
        case CSSSelector::PseudoFirstOfType:
            // first-of-type matches the first element of its type
            if (Element* parentElement = element->parentElement()) {
                bool result = isFirstOfType(element, element->tagQName());
                if (m_mode == ResolvingStyle)
                    parentElement->setChildrenAffectedByForwardPositionalRules();
                return result;
            }
            break;
        case CSSSelector::PseudoLastChild:
            // last-child matches the last child that is an element
            if (Element* parentElement = element->parentElement()) {
                bool result = parentElement->isFinishedParsingChildren() && isLastChildElement(element);
                if (m_mode == ResolvingStyle) {
                    RenderStyle* childStyle = context.elementStyle ? context.elementStyle : element->renderStyle();
                    parentElement->setChildrenAffectedByLastChildRules();
                    if (result && childStyle)
                        childStyle->setLastChildState();
                }
                return result;
            }
            break;
        case CSSSelector::PseudoLastOfType:
            // last-of-type matches the last element of its type
            if (Element* parentElement = element->parentElement()) {
                if (m_mode == ResolvingStyle)
                    parentElement->setChildrenAffectedByBackwardPositionalRules();
                if (!parentElement->isFinishedParsingChildren())
                    return false;
                return isLastOfType(element, element->tagQName());
            }
            break;
        case CSSSelector::PseudoOnlyChild:
            if (Element* parentElement = element->parentElement()) {
                bool firstChild = isFirstChildElement(element);
                bool onlyChild = firstChild && parentElement->isFinishedParsingChildren() && isLastChildElement(element);
                if (m_mode == ResolvingStyle) {
                    RenderStyle* childStyle = context.elementStyle ? context.elementStyle : element->renderStyle();
                    parentElement->setChildrenAffectedByFirstChildRules();
                    parentElement->setChildrenAffectedByLastChildRules();
                    if (firstChild && childStyle)
                        childStyle->setFirstChildState();
                    if (onlyChild && childStyle)
                        childStyle->setLastChildState();
                }
                return onlyChild;
            }
            break;
        case CSSSelector::PseudoOnlyOfType:
            // FIXME: This selector is very slow.
            if (Element* parentElement = element->parentElement()) {
                if (m_mode == ResolvingStyle) {
                    parentElement->setChildrenAffectedByForwardPositionalRules();
                    parentElement->setChildrenAffectedByBackwardPositionalRules();
                }
                if (!parentElement->isFinishedParsingChildren())
                    return false;
                return isFirstOfType(element, element->tagQName()) && isLastOfType(element, element->tagQName());
            }
            break;
        case CSSSelector::PseudoNthChild:
            if (!selector->parseNth())
                break;
            if (Element* parentElement = element->parentElement()) {
                int count = 1 + countElementsBefore(element);
                if (m_mode == ResolvingStyle) {
                    RenderStyle* childStyle = context.elementStyle ? context.elementStyle : element->renderStyle();
                    element->setChildIndex(count);
                    if (childStyle)
                        childStyle->setUnique();
                    parentElement->setChildrenAffectedByForwardPositionalRules();
                }

                if (selector->matchNth(count))
                    return true;
            }
            break;
        case CSSSelector::PseudoNthOfType:
            if (!selector->parseNth())
                break;
            if (Element* parentElement = element->parentElement()) {
                int count = 1 + countElementsOfTypeBefore(element, element->tagQName());
                if (m_mode == ResolvingStyle)
                    parentElement->setChildrenAffectedByForwardPositionalRules();

                if (selector->matchNth(count))
                    return true;
            }
            break;
        case CSSSelector::PseudoNthLastChild:
            if (!selector->parseNth())
                break;
            if (Element* parentElement = element->parentElement()) {
                if (m_mode == ResolvingStyle)
                    parentElement->setChildrenAffectedByBackwardPositionalRules();
                if (!parentElement->isFinishedParsingChildren())
                    return false;
                int count = 1 + countElementsAfter(element);
                if (selector->matchNth(count))
                    return true;
            }
            break;
        case CSSSelector::PseudoNthLastOfType:
            if (!selector->parseNth())
                break;
            if (Element* parentElement = element->parentElement()) {
                if (m_mode == ResolvingStyle)
                    parentElement->setChildrenAffectedByBackwardPositionalRules();
                if (!parentElement->isFinishedParsingChildren())
                    return false;

                int count = 1 + countElementsOfTypeAfter(element, element->tagQName());
                if (selector->matchNth(count))
                    return true;
            }
            break;
        case CSSSelector::PseudoTarget:
            if (element == element->document()->cssTarget())
                return true;
            break;
        case CSSSelector::PseudoAny:
            {
                SelectorCheckingContext subContext(context);
                subContext.isSubSelector = true;
                PseudoId ignoreDynamicPseudo = NOPSEUDO;
                for (subContext.selector = selector->selectorList()->first(); subContext.selector; subContext.selector = CSSSelectorList::next(subContext.selector)) {
                    if (match(subContext, ignoreDynamicPseudo) == SelectorMatches)
                        return true;
                }
            }
            break;
        case CSSSelector::PseudoAutofill:
            if (!element->isFormControlElement())
                break;
            if (HTMLInputElement* inputElement = element->toInputElement())
                return inputElement->isAutofilled();
            break;
        case CSSSelector::PseudoAnyLink:
        case CSSSelector::PseudoLink:
            // :visited and :link matches are separated later when applying the style. Here both classes match all links...
            return element->isLink();
        case CSSSelector::PseudoVisited:
            // ...except if :visited matching is disabled for ancestor/sibling matching.
            return element->isLink() && context.visitedMatchType == VisitedMatchEnabled;
        case CSSSelector::PseudoDrag:
            if (m_mode == ResolvingStyle) {
                if (context.elementStyle)
                    context.elementStyle->setAffectedByDrag();
                else
                    element->setChildrenAffectedByDrag(true);
            }
            if (element->renderer() && element->renderer()->isDragging())
                return true;
            break;
        case CSSSelector::PseudoFocus:
            return matchesFocusPseudoClass(element);
        case CSSSelector::PseudoHover:
            // If we're in quirks mode, then hover should never match anchors with no
            // href and *:hover should not match anything. This is important for sites like wsj.com.
            if (m_strictParsing || context.isSubSelector || (selector->m_match == CSSSelector::Tag && selector->tagQName() != anyQName() && !isHTMLAnchorElement(element)) || element->isLink()) {
                if (m_mode == ResolvingStyle) {
                    if (context.elementStyle)
                        context.elementStyle->setAffectedByHover();
                    else
                        element->setChildrenAffectedByHover(true);
                }
                if (element->hovered() || InspectorInstrumentation::forcePseudoState(element, CSSSelector::PseudoHover))
                    return true;
            }
            break;
        case CSSSelector::PseudoActive:
            // If we're in quirks mode, then :active should never match anchors with no
            // href and *:active should not match anything.
            if (m_strictParsing || context.isSubSelector || (selector->m_match == CSSSelector::Tag && selector->tagQName() != anyQName() && !isHTMLAnchorElement(element)) || element->isLink()) {
                if (m_mode == ResolvingStyle) {
                    if (context.elementStyle)
                        context.elementStyle->setAffectedByActive();
                    else
                        element->setChildrenAffectedByActive(true);
                }
                if (element->active() || InspectorInstrumentation::forcePseudoState(element, CSSSelector::PseudoActive))
                    return true;
            }
            break;
        case CSSSelector::PseudoEnabled:
            if (element->isFormControlElement() || isHTMLOptionElement(element) || isHTMLOptGroupElement(element))
                return !element->isDisabledFormControl();
            break;
        case CSSSelector::PseudoFullPageMedia:
            return element->document() && element->document()->isMediaDocument();
            break;
        case CSSSelector::PseudoDefault:
            return element->isDefaultButtonForForm();
        case CSSSelector::PseudoDisabled:
            if (element->isFormControlElement() || isHTMLOptionElement(element) || isHTMLOptGroupElement(element))
                return element->isDisabledFormControl();
            break;
        case CSSSelector::PseudoReadOnly:
            return element->matchesReadOnlyPseudoClass();
        case CSSSelector::PseudoReadWrite:
            return element->matchesReadWritePseudoClass();
        case CSSSelector::PseudoOptional:
            return element->isOptionalFormControl();
        case CSSSelector::PseudoRequired:
            return element->isRequiredFormControl();
        case CSSSelector::PseudoValid:
            element->document()->setContainsValidityStyleRules();
            return element->willValidate() && element->isValidFormControlElement();
        case CSSSelector::PseudoInvalid:
            element->document()->setContainsValidityStyleRules();
            return element->willValidate() && !element->isValidFormControlElement();
        case CSSSelector::PseudoChecked:
            {
                // Even though WinIE allows checked and indeterminate to co-exist, the CSS selector spec says that
                // you can't be both checked and indeterminate. We will behave like WinIE behind the scenes and just
                // obey the CSS spec here in the test for matching the pseudo.
                HTMLInputElement* inputElement = element->toInputElement();
                if (inputElement && inputElement->shouldAppearChecked() && !inputElement->shouldAppearIndeterminate())
                    return true;
                if (isHTMLOptionElement(element) && toHTMLOptionElement(element)->selected())
                    return true;
                break;
            }
        case CSSSelector::PseudoIndeterminate:
            return element->shouldAppearIndeterminate();
        case CSSSelector::PseudoRoot:
            if (element == element->document()->documentElement())
                return true;
            break;
        case CSSSelector::PseudoLang:
            {
                AtomicString value;
#if ENABLE(VIDEO_TRACK)
                if (element->isWebVTTElement())
                    value = toWebVTTElement(element)->language();
                else
#endif
                    value = element->computeInheritedLanguage();
                const AtomicString& argument = selector->argument();
                if (value.isEmpty() || !value.startsWith(argument, false))
                    break;
                if (value.length() != argument.length() && value[argument.length()] != '-')
                    break;
                return true;
            }
#if ENABLE(FULLSCREEN_API)
        case CSSSelector::PseudoFullScreen:
            // While a Document is in the fullscreen state, and the document's current fullscreen
            // element is an element in the document, the 'full-screen' pseudoclass applies to
            // that element. Also, an <iframe>, <object> or <embed> element whose child browsing
            // context's Document is in the fullscreen state has the 'full-screen' pseudoclass applied.
            if (element->isFrameElementBase() && element->containsFullScreenElement())
                return true;
            if (!element->document()->webkitIsFullScreen())
                return false;
            return element == element->document()->webkitCurrentFullScreenElement();
        case CSSSelector::PseudoAnimatingFullScreenTransition:
            if (element != element->document()->webkitCurrentFullScreenElement())
                return false;
            return element->document()->isAnimatingFullScreen();
        case CSSSelector::PseudoFullScreenAncestor:
            return element->containsFullScreenElement();
        case CSSSelector::PseudoFullScreenDocument:
            // While a Document is in the fullscreen state, the 'full-screen-document' pseudoclass applies
            // to all elements of that Document.
            if (!element->document()->webkitIsFullScreen())
                return false;
            return true;
#endif
#if ENABLE(IFRAME_SEAMLESS)
        case CSSSelector::PseudoSeamlessDocument:
            // While a document is rendered in a seamless iframe, the 'seamless-document' pseudoclass applies
            // to all elements of that Document.
            return element->document()->shouldDisplaySeamlesslyWithParent();
#endif
        case CSSSelector::PseudoInRange:
            element->document()->setContainsValidityStyleRules();
            return element->isInRange();
        case CSSSelector::PseudoOutOfRange:
            element->document()->setContainsValidityStyleRules();
            return element->isOutOfRange();
#if ENABLE(VIDEO_TRACK)
        case CSSSelector::PseudoFutureCue:
            return (element->isWebVTTElement() && !toWebVTTElement(element)->isPastNode());
        case CSSSelector::PseudoPastCue:
            return (element->isWebVTTElement() && toWebVTTElement(element)->isPastNode());
#endif

        case CSSSelector::PseudoScope:
            {
                const Node* contextualReferenceNode = !context.scope || context.behaviorAtBoundary == CrossesBoundary ? element->document()->documentElement() : context.scope;
                if (element == contextualReferenceNode)
                    return true;
                break;
            }

        case CSSSelector::PseudoHorizontal:
        case CSSSelector::PseudoVertical:
        case CSSSelector::PseudoDecrement:
        case CSSSelector::PseudoIncrement:
        case CSSSelector::PseudoStart:
        case CSSSelector::PseudoEnd:
        case CSSSelector::PseudoDoubleButton:
        case CSSSelector::PseudoSingleButton:
        case CSSSelector::PseudoNoButton:
        case CSSSelector::PseudoCornerPresent:
            return false;

        case CSSSelector::PseudoUnknown:
        case CSSSelector::PseudoNotParsed:
        default:
            ASSERT_NOT_REACHED();
            break;
        }
        return false;
    }
#if ENABLE(VIDEO_TRACK)
    else if (selector->m_match == CSSSelector::PseudoElement && selector->pseudoType() == CSSSelector::PseudoCue) {
        SelectorCheckingContext subContext(context);
        subContext.isSubSelector = true;

        PseudoId ignoreDynamicPseudo = NOPSEUDO;
        const CSSSelector* const & selector = context.selector;
        for (subContext.selector = selector->selectorList()->first(); subContext.selector; subContext.selector = CSSSelectorList::next(subContext.selector)) {
            if (match(subContext, ignoreDynamicPseudo) == SelectorMatches)
                return true;
        }
        return false;
    }
#endif
    // ### add the rest of the checks...
    return true;
}
bool SVGTransformable::parseTransformAttribute(SVGTransformList* list, const AtomicString& transform)
{
    const UChar* start = transform.characters();
    const UChar* end = start + transform.length();
    return parseTransformAttribute(list, start, end);
}
Beispiel #3
0
static bool attributeValueMatches(const Attribute* attributeItem, CSSSelector::Match match, const AtomicString& selectorValue, bool caseSensitive)
{
    const AtomicString& value = attributeItem->value();
    if (value.isNull())
        return false;

    switch (match) {
    case CSSSelector::Exact:
        if (caseSensitive ? selectorValue != value : !equalIgnoringCase(selectorValue, value))
            return false;
        break;
    case CSSSelector::List:
        {
            // Ignore empty selectors or selectors containing spaces
            if (selectorValue.contains(' ') || selectorValue.isEmpty())
                return false;

            unsigned startSearchAt = 0;
            while (true) {
                size_t foundPos = value.find(selectorValue, startSearchAt, caseSensitive);
                if (foundPos == notFound)
                    return false;
                if (!foundPos || value[foundPos - 1] == ' ') {
                    unsigned endStr = foundPos + selectorValue.length();
                    if (endStr == value.length() || value[endStr] == ' ')
                        break; // We found a match.
                }

                // No match. Keep looking.
                startSearchAt = foundPos + 1;
            }
            break;
        }
    case CSSSelector::Contain:
        if (!value.contains(selectorValue, caseSensitive) || selectorValue.isEmpty())
            return false;
        break;
    case CSSSelector::Begin:
        if (!value.startsWith(selectorValue, caseSensitive) || selectorValue.isEmpty())
            return false;
        break;
    case CSSSelector::End:
        if (!value.endsWith(selectorValue, caseSensitive) || selectorValue.isEmpty())
            return false;
        break;
    case CSSSelector::Hyphen:
        if (value.length() < selectorValue.length())
            return false;
        if (!value.startsWith(selectorValue, caseSensitive))
            return false;
        // It they start the same, check for exact match or following '-':
        if (value.length() != selectorValue.length() && value[selectorValue.length()] != '-')
            return false;
        break;
    case CSSSelector::PseudoClass:
    case CSSSelector::PseudoElement:
    default:
        break;
    }

    return true;
}
bool SVGTransformable::parseTransformAttribute(SVGTransformList* list, const AtomicString& transform)
{
    double x[] = {0, 0, 0, 0, 0, 0};
    int nr = 0, required = 0, optional = 0;
    
    const UChar* currTransform = transform.characters();
    const UChar* end = currTransform + transform.length();

    bool delimParsed = false;
    while (currTransform < end) {
        delimParsed = false;
        unsigned short type = SVGTransform::SVG_TRANSFORM_UNKNOWN;
        skipOptionalSpaces(currTransform, end);
        
        if (currTransform >= end)
            return false;
        
        if (*currTransform == 's') {
            if (skipString(currTransform, end, skewXDesc, sizeof(skewXDesc) / sizeof(UChar))) {
                required = 1;
                optional = 0;
                type = SVGTransform::SVG_TRANSFORM_SKEWX;
            } else if (skipString(currTransform, end, skewYDesc, sizeof(skewYDesc) / sizeof(UChar))) {
                required = 1;
                optional = 0;
                type = SVGTransform::SVG_TRANSFORM_SKEWY;
            } else if (skipString(currTransform, end, scaleDesc, sizeof(scaleDesc) / sizeof(UChar))) {
                required = 1;
                optional = 1;
                type = SVGTransform::SVG_TRANSFORM_SCALE;
            } else
                return false;
        } else if (skipString(currTransform, end, translateDesc, sizeof(translateDesc) / sizeof(UChar))) {
            required = 1;
            optional = 1;
            type = SVGTransform::SVG_TRANSFORM_TRANSLATE;
        } else if (skipString(currTransform, end, rotateDesc, sizeof(rotateDesc) / sizeof(UChar))) {
            required = 1;
            optional = 2;
            type = SVGTransform::SVG_TRANSFORM_ROTATE;
        } else if (skipString(currTransform, end, matrixDesc, sizeof(matrixDesc) / sizeof(UChar))) {
            required = 6;
            optional = 0;
            type = SVGTransform::SVG_TRANSFORM_MATRIX;
        } else 
            return false;

        if ((nr = parseTransformParamList(currTransform, end, x, required, optional)) < 0)
            return false;

        SVGTransform t;

        switch (type) {
            case SVGTransform::SVG_TRANSFORM_SKEWX:
               t.setSkewX(narrowPrecisionToFloat(x[0]));
                break;
            case SVGTransform::SVG_TRANSFORM_SKEWY:
               t.setSkewY(narrowPrecisionToFloat(x[0]));
                break;
            case SVGTransform::SVG_TRANSFORM_SCALE:
                  if (nr == 1) // Spec: if only one param given, assume uniform scaling
                      t.setScale(narrowPrecisionToFloat(x[0]), narrowPrecisionToFloat(x[0]));
                  else
                      t.setScale(narrowPrecisionToFloat(x[0]), narrowPrecisionToFloat(x[1]));
                break;
            case SVGTransform::SVG_TRANSFORM_TRANSLATE:
                  if (nr == 1) // Spec: if only one param given, assume 2nd param to be 0
                      t.setTranslate(narrowPrecisionToFloat(x[0]), 0);
                  else
                      t.setTranslate(narrowPrecisionToFloat(x[0]), narrowPrecisionToFloat(x[1]));
                break;
            case SVGTransform::SVG_TRANSFORM_ROTATE:
                  if (nr == 1)
                      t.setRotate(narrowPrecisionToFloat(x[0]), 0, 0);
                  else
                      t.setRotate(narrowPrecisionToFloat(x[0]), narrowPrecisionToFloat(x[1]), narrowPrecisionToFloat(x[2]));
                break;
            case SVGTransform::SVG_TRANSFORM_MATRIX:
                t.setMatrix(AffineTransform(x[0], x[1], x[2], x[3], x[4], x[5]));
                break;
        }

        ExceptionCode ec = 0;
        list->appendItem(t, ec);
        skipOptionalSpaces(currTransform, end);
        if (currTransform < end && *currTransform == ',') {
            delimParsed = true;
            currTransform++;
        }
        skipOptionalSpaces(currTransform, end);
    }

    return !delimParsed;
}
void ValidationMessageClientImpl::showValidationMessage(const Element& anchor, const String& message)
{
    if (message.isEmpty()) {
        hideValidationMessage(anchor);
        return;
    }
    if (!anchor.renderBox())
        return;
    if (m_currentAnchor)
        hideValidationMessage(*m_currentAnchor);
    m_currentAnchor = &anchor;
    IntRect anchorInRootView = currentView()->contentsToRootView(anchor.pixelSnappedBoundingBox());
    m_lastAnchorRectInScreen = currentView()->hostWindow()->rootViewToScreen(anchorInRootView);
    m_lastPageScaleFactor = m_webView.pageScaleFactor();
    m_message = message;

    WebTextDirection dir = m_currentAnchor->renderer()->style()->direction() == RTL ? WebTextDirectionRightToLeft : WebTextDirectionLeftToRight;
    AtomicString title = m_currentAnchor->fastGetAttribute(HTMLNames::titleAttr);
    if (m_client)
        m_client->showValidationMessage(anchorInRootView, m_message, title, dir);
    m_webView.client()->showValidationMessage(anchorInRootView, m_message, title, dir);

    const double minimumSecondToShowValidationMessage = 5.0;
    const double secondPerCharacter = 0.05;
    const double statusCheckInterval = 0.1;
    m_finishTime = monotonicallyIncreasingTime() + std::max(minimumSecondToShowValidationMessage, (message.length() + title.length()) * secondPerCharacter);
    // FIXME: We should invoke checkAnchorStatus actively when layout, scroll,
    // or page scale change happen.
    m_timer.startRepeating(statusCheckInterval);
}
Beispiel #6
0
static inline bool containsHTMLSpace(const AtomicString& string)
{
    if (LIKELY(string.is8Bit()))
        return containsHTMLSpaceTemplate<LChar>(string.characters8(), string.length());
    return containsHTMLSpaceTemplate<UChar>(string.characters16(), string.length());
}
Beispiel #7
0
bool SelectorChecker::checkPseudoClass(const SelectorCheckingContext& context) const
{
    ASSERT(context.element);
    Element& element = *context.element;
    ASSERT(context.selector);
    const CSSSelector& selector = *context.selector;
    ASSERT(selector.match() == CSSSelector::PseudoClass);

    // Normal element pseudo class checking.
    switch (selector.pseudoType()) {
    case CSSSelector::PseudoFocus:
        if (m_mode == ResolvingStyle) {
            if (context.elementStyle)
                context.elementStyle->setAffectedByFocus();
        }
        return matchesFocusPseudoClass(element);

    case CSSSelector::PseudoHover:
        if (m_mode == ResolvingStyle) {
            if (context.elementStyle)
                context.elementStyle->setAffectedByHover();
        }
        return element.hovered();

    case CSSSelector::PseudoActive:
        if (m_mode == ResolvingStyle) {
            if (context.elementStyle)
                context.elementStyle->setAffectedByActive();
        }
        return element.active();

    case CSSSelector::PseudoLang:
        {
            AtomicString value = element.computeInheritedLanguage();
            const AtomicString& argument = selector.argument();
            if (value.isEmpty() || !value.startsWith(argument, false))
                break;
            if (value.length() != argument.length() && value[argument.length()] != '-')
                break;
            return true;
        }

    case CSSSelector::PseudoUnresolved:
        return element.isUnresolvedCustomElement();

    case CSSSelector::PseudoHost:
        {
            if (m_mode == SharingRules)
                return true;
            // :host only matches a shadow host when :host is in a shadow tree of the shadow host.
            if (!context.scope)
                return false;
            const ContainerNode* shadowHost = context.scope->shadowHost();
            if (!shadowHost || shadowHost != element)
                return false;
            ASSERT(element.shadow());

            // For empty parameter case, i.e. just :host or :host().
            if (!selector.selectorList())
                return true;

            SelectorCheckingContext subContext(context);
            subContext.contextFlags = TreatShadowHostAsNormalScope;

            for (subContext.selector = selector.selectorList()->first(); subContext.selector; subContext.selector = CSSSelectorList::next(*subContext.selector)) {
                if (match(subContext))
                    return true;
            }
            return false;
        }

    case CSSSelector::PseudoUnknown:
    case CSSSelector::PseudoNotParsed:
    case CSSSelector::PseudoUserAgentCustomElement:
        return false;
    }
    ASSERT_NOT_REACHED();
    return false;
}