PassOwnPtr<CSSParserSelector> CSSSelectorParser::consumeCompoundSelector(CSSParserTokenRange& range) { OwnPtr<CSSParserSelector> selector; AtomicString namespacePrefix; AtomicString elementName; bool hasNamespace; if (!consumeName(range, elementName, namespacePrefix, hasNamespace)) { selector = consumeSimpleSelector(range); if (!selector) return nullptr; } if (m_context.isHTMLDocument()) elementName = elementName.lower(); while (OwnPtr<CSSParserSelector> nextSelector = consumeSimpleSelector(range)) { if (selector) selector = rewriteSpecifiers(selector.release(), nextSelector.release()); else selector = nextSelector.release(); } if (!selector) { if (hasNamespace) return CSSParserSelector::create(determineNameInNamespace(namespacePrefix, elementName)); return CSSParserSelector::create(QualifiedName(nullAtom, elementName, m_defaultNamespace)); } if (elementName.isNull()) rewriteSpecifiersWithNamespaceIfNeeded(selector.get()); else rewriteSpecifiersWithElementName(namespacePrefix, elementName, selector.get()); return selector.release(); }
void HTMLObjectElement::parseAttribute(const QualifiedName& name, const AtomicString& value) { if (name == formAttr) formAttributeChanged(); else if (name == typeAttr) { m_serviceType = value.lower(); size_t pos = m_serviceType.find(";"); if (pos != notFound) m_serviceType = m_serviceType.left(pos); if (renderer()) setNeedsWidgetUpdate(true); } else if (name == dataAttr) { m_url = stripLeadingAndTrailingHTMLSpaces(value); if (renderer()) { setNeedsWidgetUpdate(true); if (isImageType()) { if (!m_imageLoader) m_imageLoader = adoptPtr(new HTMLImageLoader(this)); m_imageLoader->updateFromElementIgnoringPreviousError(); } } } else if (name == classidAttr) { m_classId = value; if (renderer()) setNeedsWidgetUpdate(true); } else if (name == onbeforeloadAttr) setAttributeEventListener(eventNames().beforeloadEvent, name, value); else HTMLPlugInImageElement::parseAttribute(name, value); }
void HTMLObjectElement::parseAttribute(const QualifiedName& name, const AtomicString& value) { if (name == formAttr) formAttributeChanged(); else if (name == typeAttr) { m_serviceType = value.lower(); size_t pos = m_serviceType.find(";"); if (pos != kNotFound) m_serviceType = m_serviceType.left(pos); // FIXME: What is the right thing to do here? Should we supress the // reload stuff when a persistable widget-type is specified? reloadPluginOnAttributeChange(name); if (!renderer()) requestPluginCreationWithoutRendererIfPossible(); } else if (name == dataAttr) { m_url = stripLeadingAndTrailingHTMLSpaces(value); if (renderer() && isImageType()) { setNeedsWidgetUpdate(true); if (!m_imageLoader) m_imageLoader = HTMLImageLoader::create(this); m_imageLoader->updateFromElement(ImageLoader::UpdateIgnorePreviousError); } else { reloadPluginOnAttributeChange(name); } } else if (name == classidAttr) { m_classId = value; reloadPluginOnAttributeChange(name); } else { HTMLPlugInElement::parseAttribute(name, value); } }
void HTMLTrackElement::parseAttribute(const QualifiedName& name, const AtomicString& value) { if (RuntimeEnabledFeatures::webkitVideoTrackEnabled()) { if (name == srcAttr) { if (!value.isEmpty() && mediaElement()) scheduleLoad(); // 4.8.10.12.3 Sourcing out-of-band text tracks // As the kind, label, and srclang attributes are set, changed, or removed, the text track must update accordingly... } else if (name == kindAttr) track()->setKind(value.lower()); else if (name == labelAttr) track()->setLabel(value); else if (name == srclangAttr) track()->setLanguage(value); else if (name == defaultAttr) track()->setIsDefault(!value.isNull()); } if (name == onloadAttr) setAttributeEventListener(eventNames().loadEvent, createAttributeEventListener(this, name, value)); else if (name == onerrorAttr) setAttributeEventListener(eventNames().errorEvent, createAttributeEventListener(this, name, value)); else HTMLElement::parseAttribute(name, value); }
PassRefPtr<CustomElementConstructor> CustomElementRegistry::registerElement(ScriptState* state, const AtomicString& name, const Dictionary& options, ExceptionCode& ec) { RefPtr<CustomElementRegistry> protect(this); if (!CustomElementHelpers::isFeatureAllowed(state)) return 0; AtomicString lowerName = name.lower(); if (!isValidName(lowerName)) { ec = INVALID_CHARACTER_ERR; return 0; } ScriptValue prototypeValue; if (!options.get("prototype", prototypeValue)) { // FIXME: Implement the default value handling. // Currently default value of the "prototype" parameter, which // is HTMLSpanElement.prototype, has an ambiguity about its // behavior. The spec should be fixed before WebKit implements // it. https://www.w3.org/Bugs/Public/show_bug.cgi?id=20801 ec = INVALID_STATE_ERR; return 0; } AtomicString namespaceURI; if (!CustomElementHelpers::isValidPrototypeParameter(prototypeValue, state, namespaceURI)) { ec = INVALID_STATE_ERR; return 0; } if (m_names.contains(lowerName)) { ec = INVALID_STATE_ERR; return 0; } const QualifiedName* localNameFound = CustomElementHelpers::findLocalName(prototypeValue); QualifiedName typeName(nullAtom, lowerName, namespaceURI); QualifiedName localNameToUse = localNameFound ? *localNameFound : typeName; if (find(typeName, localNameToUse)) { ec = INVALID_STATE_ERR; return 0; } // A script execution could happen in isValidPrototypeParameter(), which kills the document. if (!document()) { ec = INVALID_STATE_ERR; return 0; } RefPtr<CustomElementConstructor> constructor = CustomElementConstructor::create(state, document(), typeName, localNameToUse, prototypeValue); if (!constructor) { ec = INVALID_STATE_ERR; return 0; } m_constructors.add(std::make_pair(constructor->typeName(), constructor->localName()), constructor); m_names.add(lowerName); return constructor; }
void HTMLTrackElement::parseAttribute(const QualifiedName& name, const AtomicString& oldValue, const AtomicString& value) { if (name == srcAttr) { if (!value.isEmpty()) scheduleLoad(); else if (m_track) m_track->removeAllCues(); // 4.8.10.12.3 Sourcing out-of-band text tracks // As the kind, label, and srclang attributes are set, changed, or removed, // the text track must update accordingly... } else if (name == kindAttr) { AtomicString lowerCaseValue = value.lower(); // 'missing value default' ("subtitles") if (lowerCaseValue.isNull()) lowerCaseValue = TextTrack::subtitlesKeyword(); // 'invalid value default' ("metadata") else if (!TextTrack::isValidKindKeyword(lowerCaseValue)) lowerCaseValue = TextTrack::metadataKeyword(); track()->setKind(lowerCaseValue); } else if (name == labelAttr) { track()->setLabel(value); } else if (name == srclangAttr) { track()->setLanguage(value); } else if (name == idAttr) { track()->setId(value); } HTMLElement::parseAttribute(name, oldValue, value); }
PassRefPtr<Element> HTMLDocument::createElement(const AtomicString& name, ExceptionCode& ec) { if (!isValidName(name)) { ec = INVALID_CHARACTER_ERR; return 0; } return HTMLElementFactory::createHTMLElement(QualifiedName(nullAtom, name.lower(), xhtmlNamespaceURI), this, 0, false); }
void CustomElementRegistry::registerElement(CustomElementConstructorBuilder* constructorBuilder, const AtomicString& userSuppliedName, ExceptionCode& ec) { RefPtr<CustomElementRegistry> protect(this); if (!constructorBuilder->isFeatureAllowed()) return; AtomicString type = userSuppliedName.lower(); if (!isValidName(type)) { ec = INVALID_CHARACTER_ERR; return; } if (!constructorBuilder->validateOptions()) { ec = INVALID_STATE_ERR; return; } QualifiedName tagName = nullQName(); if (!constructorBuilder->findTagName(type, tagName)) { ec = NAMESPACE_ERR; return; } ASSERT(tagName.namespaceURI() == HTMLNames::xhtmlNamespaceURI || tagName.namespaceURI() == SVGNames::svgNamespaceURI); if (m_definitions.contains(type)) { ec = INVALID_STATE_ERR; return; } RefPtr<CustomElementCallback> lifecycleCallbacks = constructorBuilder->createCallback(document()); // Consulting the constructor builder could execute script and // kill the document. if (!document()) { ec = INVALID_STATE_ERR; return; } RefPtr<CustomElementDefinition> definition = CustomElementDefinition::create(type, tagName.localName(), tagName.namespaceURI(), lifecycleCallbacks); if (!constructorBuilder->createConstructor(document(), definition.get())) { ec = NOT_SUPPORTED_ERR; return; } m_definitions.add(definition->type(), definition); // Upgrade elements that were waiting for this definition. CustomElementUpgradeCandidateMap::ElementSet upgradeCandidates = m_candidates.takeUpgradeCandidatesFor(definition.get()); constructorBuilder->didRegisterDefinition(definition.get(), upgradeCandidates); for (CustomElementUpgradeCandidateMap::ElementSet::iterator it = upgradeCandidates.begin(); it != upgradeCandidates.end(); ++it) { (*it)->setNeedsStyleRecalc(); // :unresolved has changed enqueueReadyCallback(lifecycleCallbacks.get(), *it); } }
CacheControlHeader parseCacheControlDirectives(const AtomicString& cacheControlValue, const AtomicString& pragmaValue) { CacheControlHeader cacheControlHeader; cacheControlHeader.parsed = true; cacheControlHeader.maxAge = std::numeric_limits<double>::quiet_NaN(); cacheControlHeader.staleWhileRevalidate = std::numeric_limits<double>::quiet_NaN(); DEFINE_STATIC_LOCAL(const AtomicString, noCacheDirective, ("no-cache", AtomicString::ConstructFromLiteral)); DEFINE_STATIC_LOCAL(const AtomicString, noStoreDirective, ("no-store", AtomicString::ConstructFromLiteral)); DEFINE_STATIC_LOCAL(const AtomicString, mustRevalidateDirective, ("must-revalidate", AtomicString::ConstructFromLiteral)); DEFINE_STATIC_LOCAL(const AtomicString, maxAgeDirective, ("max-age", AtomicString::ConstructFromLiteral)); DEFINE_STATIC_LOCAL(const AtomicString, staleWhileRevalidateDirective, ("stale-while-revalidate", AtomicString::ConstructFromLiteral)); if (!cacheControlValue.isEmpty()) { Vector<std::pair<String, String>> directives; parseCacheHeader(cacheControlValue, directives); size_t directivesSize = directives.size(); for (size_t i = 0; i < directivesSize; ++i) { // RFC2616 14.9.1: A no-cache directive with a value is only meaningful for proxy caches. // It should be ignored by a browser level cache. if (equalIgnoringCase(directives[i].first, noCacheDirective) && directives[i].second.isEmpty()) { cacheControlHeader.containsNoCache = true; } else if (equalIgnoringCase(directives[i].first, noStoreDirective)) { cacheControlHeader.containsNoStore = true; } else if (equalIgnoringCase(directives[i].first, mustRevalidateDirective)) { cacheControlHeader.containsMustRevalidate = true; } else if (equalIgnoringCase(directives[i].first, maxAgeDirective)) { if (!std::isnan(cacheControlHeader.maxAge)) { // First max-age directive wins if there are multiple ones. continue; } bool ok; double maxAge = directives[i].second.toDouble(&ok); if (ok) cacheControlHeader.maxAge = maxAge; } else if (equalIgnoringCase(directives[i].first, staleWhileRevalidateDirective)) { if (!std::isnan(cacheControlHeader.staleWhileRevalidate)) { // First stale-while-revalidate directive wins if there are multiple ones. continue; } bool ok; double staleWhileRevalidate = directives[i].second.toDouble(&ok); if (ok) cacheControlHeader.staleWhileRevalidate = staleWhileRevalidate; } } } if (!cacheControlHeader.containsNoCache) { // Handle Pragma: no-cache // This is deprecated and equivalent to Cache-control: no-cache // Don't bother tokenizing the value, it is not important cacheControlHeader.containsNoCache = pragmaValue.lower().contains(noCacheDirective); } return cacheControlHeader; }
std::unique_ptr<CSSParserSelector> CSSSelectorParser::consumeCompoundSelector( CSSParserTokenRange& range) { std::unique_ptr<CSSParserSelector> compoundSelector; AtomicString namespacePrefix; AtomicString elementName; CSSSelector::PseudoType compoundPseudoElement = CSSSelector::PseudoUnknown; if (!consumeName(range, elementName, namespacePrefix)) { compoundSelector = consumeSimpleSelector(range); if (!compoundSelector) return nullptr; if (compoundSelector->match() == CSSSelector::PseudoElement) compoundPseudoElement = compoundSelector->pseudoType(); } if (m_context.isHTMLDocument()) elementName = elementName.lower(); while (std::unique_ptr<CSSParserSelector> simpleSelector = consumeSimpleSelector(range)) { // TODO([email protected]): crbug.com/578131 // The UASheetMode check is a work-around to allow this selector in // mediaControls(New).css: // video::-webkit-media-text-track-region-container.scrolling if (m_context.mode() != UASheetMode && !isSimpleSelectorValidAfterPseudoElement(*simpleSelector.get(), compoundPseudoElement)) { m_failedParsing = true; return nullptr; } if (simpleSelector->match() == CSSSelector::PseudoElement) compoundPseudoElement = simpleSelector->pseudoType(); if (compoundSelector) compoundSelector = addSimpleSelectorToCompound( std::move(compoundSelector), std::move(simpleSelector)); else compoundSelector = std::move(simpleSelector); } if (!compoundSelector) { AtomicString namespaceURI = determineNamespace(namespacePrefix); if (namespaceURI.isNull()) { m_failedParsing = true; return nullptr; } if (namespaceURI == defaultNamespace()) namespacePrefix = nullAtom; return CSSParserSelector::create( QualifiedName(namespacePrefix, elementName, namespaceURI)); } prependTypeSelectorIfNeeded(namespacePrefix, elementName, compoundSelector.get()); return splitCompoundAtImplicitShadowCrossingCombinator( std::move(compoundSelector)); }
PassRefPtrWillBeRawPtr<StyleRulePage> CSSParserImpl::consumePageRule(CSSParserTokenRange prelude, CSSParserTokenRange block) { // We only support a small subset of the css-page spec. prelude.consumeWhitespace(); AtomicString typeSelector; if (prelude.peek().type() == IdentToken) typeSelector = prelude.consume().value(); AtomicString pseudo; if (prelude.peek().type() == ColonToken) { prelude.consume(); if (prelude.peek().type() != IdentToken) return nullptr; // Parse error; expected ident token following colon in @page header pseudo = prelude.consume().value(); } prelude.consumeWhitespace(); if (!prelude.atEnd()) return nullptr; // Parse error; extra tokens in @page header OwnPtr<CSSParserSelector> selector; if (!typeSelector.isNull() && pseudo.isNull()) { selector = CSSParserSelector::create(QualifiedName(nullAtom, typeSelector, m_defaultNamespace)); } else { selector = CSSParserSelector::create(); if (!pseudo.isNull()) { selector->setMatch(CSSSelector::PagePseudoClass); selector->setValue(pseudo.lower()); if (selector->pseudoType() == CSSSelector::PseudoUnknown) return nullptr; // Parse error; unknown page pseudo-class } if (!typeSelector.isNull()) selector->prependTagSelector(QualifiedName(nullAtom, typeSelector, m_defaultNamespace)); } if (m_observerWrapper) { unsigned endOffset = m_observerWrapper->endOffset(prelude); m_observerWrapper->observer().startRuleHeader(StyleRule::Page, m_observerWrapper->startOffset(prelude)); m_observerWrapper->observer().endRuleHeader(endOffset); } selector->setForPage(); RefPtrWillBeRawPtr<StyleRulePage> pageRule = StyleRulePage::create(); Vector<OwnPtr<CSSParserSelector>> selectorVector; selectorVector.append(selector.release()); pageRule->parserAdoptSelectorVector(selectorVector); consumeDeclarationList(block, StyleRule::Style); pageRule->setProperties(createStylePropertySet(m_parsedProperties, m_context.mode())); m_parsedProperties.clear(); return pageRule.release(); }
std::unique_ptr<CSSParserSelector> CSSSelectorParser::consumeAttribute( CSSParserTokenRange& range) { ASSERT(range.peek().type() == LeftBracketToken); CSSParserTokenRange block = range.consumeBlock(); block.consumeWhitespace(); AtomicString namespacePrefix; AtomicString attributeName; if (!consumeName(block, attributeName, namespacePrefix)) return nullptr; block.consumeWhitespace(); if (m_context.isHTMLDocument()) attributeName = attributeName.lower(); AtomicString namespaceURI = determineNamespace(namespacePrefix); if (namespaceURI.isNull()) return nullptr; QualifiedName qualifiedName = namespacePrefix.isNull() ? QualifiedName(nullAtom, attributeName, nullAtom) : QualifiedName(namespacePrefix, attributeName, namespaceURI); std::unique_ptr<CSSParserSelector> selector = CSSParserSelector::create(); if (block.atEnd()) { selector->setAttribute(qualifiedName, CSSSelector::CaseSensitive); selector->setMatch(CSSSelector::AttributeSet); return selector; } selector->setMatch(consumeAttributeMatch(block)); const CSSParserToken& attributeValue = block.consumeIncludingWhitespace(); if (attributeValue.type() != IdentToken && attributeValue.type() != StringToken) return nullptr; selector->setValue(attributeValue.value().toAtomicString()); selector->setAttribute(qualifiedName, consumeAttributeFlags(block)); if (!block.atEnd()) return nullptr; return selector; }
void HTMLTrackElement::parseAttribute(const QualifiedName& name, const AtomicString& oldValue, const AtomicString& value) { if (name == srcAttr) { if (!value.isEmpty()) scheduleLoad(); else if (m_track) m_track->removeAllCues(); // 4.8.10.12.3 Sourcing out-of-band text tracks // As the kind, label, and srclang attributes are set, changed, or removed, the text track must update accordingly... } else if (name == kindAttr) { track()->setKind(value.lower()); } else if (name == labelAttr) { track()->setLabel(value); } else if (name == srclangAttr) { track()->setLanguage(value); } else if (name == idAttr) { track()->setId(value); } HTMLElement::parseAttribute(name, oldValue, value); }
void HTMLLinkElement::parseAttribute(const QualifiedName& name, const AtomicString& oldValue, const AtomicString& value) { if (name == relAttr) { m_relAttribute = LinkRelAttribute(value); m_relList->setRelValues(value); process(); } else if (name == hrefAttr) { // Log href attribute before logging resource fetching in process(). logUpdateAttributeIfIsolatedWorldAndInDocument("link", hrefAttr, oldValue, value); process(); } else if (name == typeAttr) { m_type = value; process(); } else if (name == asAttr) { m_as = value; process(); } else if (name == sizesAttr) { m_sizes->setValue(value); } else if (name == mediaAttr) { m_media = value.lower(); process(); } else if (name == scopeAttr) { m_scope = value; process(); } else if (name == disabledAttr) { UseCounter::count(document(), UseCounter::HTMLLinkElementDisabled); if (LinkStyle* link = linkStyle()) link->setDisabledState(!value.isNull()); } else { if (name == titleAttr) { if (LinkStyle* link = linkStyle()) link->setSheetTitle(value, StyleEngine::UpdateActiveSheets); } HTMLElement::parseAttribute(name, oldValue, value); } }
void HTMLTrackElement::parseAttribute(const QualifiedName& name, const AtomicString& value) { if (RuntimeEnabledFeatures::sharedFeatures().webkitVideoTrackEnabled()) { if (name == srcAttr) { if (!value.isEmpty()) scheduleLoad(); else if (m_track) m_track->removeAllCues(); // 4.8.10.12.3 Sourcing out-of-band text tracks // As the kind, label, and srclang attributes are set, changed, or removed, the text track must update accordingly... } else if (name == kindAttr) track()->setKind(value.lower()); else if (name == labelAttr) track()->setLabel(value); else if (name == srclangAttr) track()->setLanguage(value); else if (name == defaultAttr) track()->setIsDefault(!value.isNull()); } HTMLElement::parseAttribute(name, value); }
bool CustomElementConstructorBuilder::validateOptions(const AtomicString& type, QualifiedName& tagName, ExceptionState& exceptionState) { ASSERT(m_prototype.IsEmpty()); v8::TryCatch tryCatch; ScriptValue prototypeScriptValue; if (m_options->get("prototype", prototypeScriptValue) && !prototypeScriptValue.isNull()) { ASSERT(!tryCatch.HasCaught()); if (!prototypeScriptValue.isObject()) { CustomElementException::throwException(CustomElementException::PrototypeNotAnObject, type, exceptionState); tryCatch.ReThrow(); return false; } m_prototype = prototypeScriptValue.v8Value().As<v8::Object>(); } else if (!tryCatch.HasCaught()) { m_prototype = v8::Object::New(m_scriptState->isolate()); v8::Local<v8::Object> basePrototype = m_scriptState->perContextData()->prototypeForType(&V8HTMLElement::wrapperTypeInfo); if (!basePrototype.IsEmpty()) m_prototype->SetPrototype(basePrototype); } if (tryCatch.HasCaught()) { tryCatch.ReThrow(); return false; } AtomicString extends; bool extendsProvidedAndNonNull = m_options->get("extends", extends); if (tryCatch.HasCaught()) { tryCatch.ReThrow(); return false; } if (!m_scriptState->perContextData()) { // FIXME: This should generate an InvalidContext exception at a later point. CustomElementException::throwException(CustomElementException::ContextDestroyedCheckingPrototype, type, exceptionState); tryCatch.ReThrow(); return false; } AtomicString namespaceURI = HTMLNames::xhtmlNamespaceURI; if (hasValidPrototypeChainFor(&V8SVGElement::wrapperTypeInfo)) namespaceURI = SVGNames::svgNamespaceURI; ASSERT(!tryCatch.HasCaught()); AtomicString localName; if (extendsProvidedAndNonNull) { localName = extends.lower(); if (!Document::isValidName(localName)) { CustomElementException::throwException(CustomElementException::ExtendsIsInvalidName, type, exceptionState); tryCatch.ReThrow(); return false; } if (CustomElement::isValidName(localName)) { CustomElementException::throwException(CustomElementException::ExtendsIsCustomElementName, type, exceptionState); tryCatch.ReThrow(); return false; } } else { if (namespaceURI == SVGNames::svgNamespaceURI) { CustomElementException::throwException(CustomElementException::ExtendsIsInvalidName, type, exceptionState); tryCatch.ReThrow(); return false; } localName = type; } if (!extendsProvidedAndNonNull) m_wrapperType = &V8HTMLElement::wrapperTypeInfo; else if (namespaceURI == HTMLNames::xhtmlNamespaceURI) m_wrapperType = findWrapperTypeForHTMLTagName(localName); else m_wrapperType = findWrapperTypeForSVGTagName(localName); ASSERT(!tryCatch.HasCaught()); ASSERT(m_wrapperType); tagName = QualifiedName(nullAtom, localName, namespaceURI); return m_wrapperType; }
HTMLTagCollection::HTMLTagCollection(ContainerNode& rootNode, const AtomicString& localName) : TagCollection(rootNode, HTMLTagCollectionType, starAtom, localName) , m_loweredLocalName(localName.lower()) { ASSERT(rootNode.document().isHTMLDocument()); }
HTMLTagNodeList::HTMLTagNodeList(ContainerNode& rootNode, const AtomicString& localName) : TagNodeList(rootNode, Type::HTMLTagNodeListType, starAtom, localName) , m_loweredLocalName(localName.lower()) { }
HTMLTagNodeList::HTMLTagNodeList(PassRefPtr<ContainerNode> rootNode, const AtomicString& localName) : TagNodeList(rootNode, HTMLTagNodeListType, starAtom, localName) , m_loweredLocalName(localName.lower()) { }
HTMLTagCollection::HTMLTagCollection(ContainerNode& rootNode, const AtomicString& localName) : TagCollection(rootNode, HTMLTagCollectionType, starAtom, localName) , m_loweredLocalName(localName.lower()) { }