static bool parseQualifiedNameInternal(const AtomicString& qualifiedName, const CharType* characters, unsigned length, AtomicString& prefix, AtomicString& localName, ExceptionState& exceptionState) { bool nameStart = true; bool sawColon = false; int colonPos = 0; for (unsigned i = 0; i < length;) { UChar32 c; U16_NEXT(characters, i, length, c) if (c == ':') { if (sawColon) { exceptionState.ThrowDOMException(NamespaceError, "The qualified name provided ('" + qualifiedName + "') contains multiple colons."); return false; // multiple colons: not allowed } nameStart = true; sawColon = true; colonPos = i - 1; } else if (nameStart) { if (!isValidNameStart(c)) { StringBuilder message; message.appendLiteral("The qualified name provided ('"); message.append(qualifiedName); message.appendLiteral("') contains the invalid name-start character '"); message.append(c); message.appendLiteral("'."); exceptionState.ThrowDOMException(InvalidCharacterError, message.toString()); return false; } nameStart = false; } else { if (!isValidNamePart(c)) { StringBuilder message; message.appendLiteral("The qualified name provided ('"); message.append(qualifiedName); message.appendLiteral("') contains the invalid character '"); message.append(c); message.appendLiteral("'."); exceptionState.ThrowDOMException(InvalidCharacterError, message.toString()); return false; } } } if (!sawColon) { prefix = nullAtom; localName = qualifiedName; } else { prefix = AtomicString(characters, colonPos); if (prefix.isEmpty()) { exceptionState.ThrowDOMException(NamespaceError, "The qualified name provided ('" + qualifiedName + "') has an empty namespace prefix."); return false; } int prefixStart = colonPos + 1; localName = AtomicString(characters + prefixStart, length - prefixStart); } if (localName.isEmpty()) { exceptionState.ThrowDOMException(NamespaceError, "The qualified name provided ('" + qualifiedName + "') has an empty local name."); return false; } return true; }
void DOMTokenList::remove(const AtomicString& token, ExceptionState& es) { Vector<String> tokens; tokens.append(token.string()); remove(tokens, es); }
size_t parseHTTPHeader(const char* start, size_t length, String& failureReason, AtomicString& nameStr, String& valueStr) { const char* p = start; const char* end = start + length; Vector<char> name; Vector<char> value; nameStr = AtomicString(); valueStr = String(); for (; p < end; p++) { switch (*p) { case '\r': if (name.isEmpty()) { if (p + 1 < end && *(p + 1) == '\n') return (p + 2) - start; failureReason = "CR doesn't follow LF at " + trimInputSample(p, end - p); return 0; } failureReason = "Unexpected CR in name at " + trimInputSample(name.data(), name.size()); return 0; case '\n': failureReason = "Unexpected LF in name at " + trimInputSample(name.data(), name.size()); return 0; case ':': break; default: name.append(*p); continue; } if (*p == ':') { ++p; break; } } for (; p < end && *p == 0x20; p++) { } for (; p < end; p++) { switch (*p) { case '\r': break; case '\n': failureReason = "Unexpected LF in value at " + trimInputSample(value.data(), value.size()); return 0; default: value.append(*p); } if (*p == '\r') { ++p; break; } } if (p >= end || *p != '\n') { failureReason = "CR doesn't follow LF after value at " + trimInputSample(p, end - p); return 0; } nameStr = AtomicString::fromUTF8(name.data(), name.size()); valueStr = String::fromUTF8(value.data(), value.size()); if (nameStr.isNull()) { failureReason = "Invalid UTF-8 sequence in header name"; return 0; } if (valueStr.isNull()) { failureReason = "Invalid UTF-8 sequence in header value"; return 0; } return p - start; }
String::String(const AtomicString &s) { m_px = s.get(); }
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()) { if (!element->hasAttributes()) return false; const QualifiedName& attr = selector->attribute(); bool caseSensitive = !m_documentIsHTML || HTMLDocument::isCaseSensitiveAttribute(attr); if (!anyAttributeMatches(element, selector, attr, 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; }
static bool isCSS(Element* element, const AtomicString& type) { return type.isEmpty() || (element->isHTMLElement() ? equalIgnoringCase(type, "text/css") : (type == "text/css")); }
void StyleSheetContents::parserAddNamespace(const AtomicString& prefix, const AtomicString& uri) { if (uri.isNull() || prefix.isNull()) return; m_namespaces.add(prefix, uri); }
PassRefPtr<HTMLFormControlElement> HTMLFormElement::elementForAlias(const AtomicString& alias) { if (alias.isEmpty() || !m_elementAliases) return 0; return m_elementAliases->get(alias.impl()); }
void ArgumentCoder<AtomicString>::encode(ArgumentEncoder& encoder, const AtomicString& atomicString) { encoder << atomicString.string(); }
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; }
void HTMLBodyElement::parseAttribute(const QualifiedName& name, const AtomicString& value) { if (name == vlinkAttr || name == alinkAttr || name == linkAttr) { if (value.isNull()) { if (name == linkAttr) document().textLinkColors().resetLinkColor(); else if (name == vlinkAttr) document().textLinkColors().resetVisitedLinkColor(); else document().textLinkColors().resetActiveLinkColor(); } else { RGBA32 color; if (BisonCSSParser::parseColor(color, value, !document().inQuirksMode())) { if (name == linkAttr) document().textLinkColors().setLinkColor(color); else if (name == vlinkAttr) document().textLinkColors().setVisitedLinkColor(color); else document().textLinkColors().setActiveLinkColor(color); } } setNeedsStyleRecalc(SubtreeStyleChange); } else if (name == onloadAttr) document().setWindowAttributeEventListener(EventTypeNames::load, createAttributeEventListener(document().frame(), name, value)); else if (name == onbeforeunloadAttr) document().setWindowAttributeEventListener(EventTypeNames::beforeunload, createAttributeEventListener(document().frame(), name, value)); else if (name == onunloadAttr) document().setWindowAttributeEventListener(EventTypeNames::unload, createAttributeEventListener(document().frame(), name, value)); else if (name == onpagehideAttr) document().setWindowAttributeEventListener(EventTypeNames::pagehide, createAttributeEventListener(document().frame(), name, value)); else if (name == onpageshowAttr) document().setWindowAttributeEventListener(EventTypeNames::pageshow, createAttributeEventListener(document().frame(), name, value)); else if (name == onpopstateAttr) document().setWindowAttributeEventListener(EventTypeNames::popstate, createAttributeEventListener(document().frame(), name, value)); else if (name == onblurAttr) document().setWindowAttributeEventListener(EventTypeNames::blur, createAttributeEventListener(document().frame(), name, value)); else if (name == onerrorAttr) document().setWindowAttributeEventListener(EventTypeNames::error, createAttributeEventListener(document().frame(), name, value)); else if (name == onfocusAttr) document().setWindowAttributeEventListener(EventTypeNames::focus, createAttributeEventListener(document().frame(), name, value)); else if (RuntimeEnabledFeatures::orientationEventEnabled() && name == onorientationchangeAttr) document().setWindowAttributeEventListener(EventTypeNames::orientationchange, createAttributeEventListener(document().frame(), name, value)); else if (name == onhashchangeAttr) document().setWindowAttributeEventListener(EventTypeNames::hashchange, createAttributeEventListener(document().frame(), name, value)); else if (name == onmessageAttr) document().setWindowAttributeEventListener(EventTypeNames::message, createAttributeEventListener(document().frame(), name, value)); else if (name == onresizeAttr) document().setWindowAttributeEventListener(EventTypeNames::resize, createAttributeEventListener(document().frame(), name, value)); else if (name == onscrollAttr) document().setWindowAttributeEventListener(EventTypeNames::scroll, createAttributeEventListener(document().frame(), name, value)); else if (name == onselectionchangeAttr) document().setAttributeEventListener(EventTypeNames::selectionchange, createAttributeEventListener(document().frame(), name, value)); else if (name == onstorageAttr) document().setWindowAttributeEventListener(EventTypeNames::storage, createAttributeEventListener(document().frame(), name, value)); else if (name == ononlineAttr) document().setWindowAttributeEventListener(EventTypeNames::online, createAttributeEventListener(document().frame(), name, value)); else if (name == onofflineAttr) document().setWindowAttributeEventListener(EventTypeNames::offline, createAttributeEventListener(document().frame(), name, value)); else HTMLElement::parseAttribute(name, value); }
bool SVGTransformable::parseTransformAttribute(SVGTransformList* list, const AtomicString& transform) { const UChar* start = transform.characters(); const UChar* end = start + transform.length(); return parseTransformAttribute(list, start, end); }
JSValue JSDOMWindow::open(ExecState* exec, const ArgList& args) { Frame* frame = impl()->frame(); if (!frame) return jsUndefined(); Frame* lexicalFrame = toLexicalFrame(exec); if (!lexicalFrame) return jsUndefined(); Frame* dynamicFrame = toDynamicFrame(exec); if (!dynamicFrame) return jsUndefined(); Page* page = frame->page(); String urlString = valueToStringWithUndefinedOrNullCheck(exec, args.at(0)); AtomicString frameName = args.at(1).isUndefinedOrNull() ? "_blank" : AtomicString(args.at(1).toString(exec)); // Because FrameTree::find() returns true for empty strings, we must check for empty framenames. // Otherwise, illegitimate window.open() calls with no name will pass right through the popup blocker. if (!DOMWindow::allowPopUp(dynamicFrame) && (frameName.isEmpty() || !frame->tree()->find(frameName))) return jsUndefined(); // Get the target frame for the special cases of _top and _parent. In those // cases, we can schedule a location change right now and return early. bool topOrParent = false; if (frameName == "_top") { frame = frame->tree()->top(); topOrParent = true; } else if (frameName == "_parent") { if (Frame* parent = frame->tree()->parent()) frame = parent; topOrParent = true; } if (topOrParent) { if (!shouldAllowNavigation(exec, frame)) return jsUndefined(); String completedURL; if (!urlString.isEmpty()) completedURL = completeURL(exec, urlString).string(); const JSDOMWindow* targetedWindow = toJSDOMWindow(frame); if (!completedURL.isEmpty() && (!protocolIsJavaScript(completedURL) || (targetedWindow && targetedWindow->allowsAccessFrom(exec)))) { bool userGesture = processingUserGesture(exec); // For whatever reason, Firefox uses the dynamicGlobalObject to // determine the outgoingReferrer. We replicate that behavior // here. String referrer = dynamicFrame->loader()->outgoingReferrer(); frame->loader()->scheduleLocationChange(completedURL, referrer, !lexicalFrame->script()->anyPageIsProcessingUserGesture(), false, userGesture); } return toJS(exec, frame->domWindow()); } // In the case of a named frame or a new window, we'll use the createWindow() helper WindowFeatures windowFeatures(valueToStringWithUndefinedOrNullCheck(exec, args.at(2))); FloatRect windowRect(windowFeatures.xSet ? windowFeatures.x : 0, windowFeatures.ySet ? windowFeatures.y : 0, windowFeatures.widthSet ? windowFeatures.width : 0, windowFeatures.heightSet ? windowFeatures.height : 0); DOMWindow::adjustWindowRect(screenAvailableRect(page ? page->mainFrame()->view() : 0), windowRect, windowRect); windowFeatures.x = windowRect.x(); windowFeatures.y = windowRect.y(); windowFeatures.height = windowRect.height(); windowFeatures.width = windowRect.width(); frame = createWindow(exec, lexicalFrame, dynamicFrame, frame, urlString, frameName, windowFeatures, JSValue()); if (!frame) return jsUndefined(); return toJS(exec, frame->domWindow()); }
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 HTMLDocument::addItemToMap(HashCountedSet<AtomicStringImpl*>& map, const AtomicString& name) { if (name.isEmpty()) return; map.add(name.impl()); }
void TreeScope::addElementByName(const AtomicString& name, Element* element) { if (!m_elementsByName) m_elementsByName = adoptPtr(new DocumentOrderedMap); m_elementsByName->add(name.impl(), element); }
void HTMLDocument::removeItemFromMap(HashCountedSet<AtomicStringImpl*>& map, const AtomicString& name) { if (name.isEmpty()) return; map.remove(name.impl()); }
void TreeScope::removeElementByName(const AtomicString& name, Element* element) { if (!m_elementsByName) return; m_elementsByName->remove(name.impl(), element); }
void DocumentStyleSheetCollection::collectActiveStyleSheets(Vector<RefPtr<StyleSheet> >& sheets) { if (m_document->settings() && !m_document->settings()->authorAndUserStylesEnabled()) return; StyleSheetCandidateListHashSet::iterator begin = m_styleSheetCandidateNodes.begin(); StyleSheetCandidateListHashSet::iterator end = m_styleSheetCandidateNodes.end(); for (StyleSheetCandidateListHashSet::iterator it = begin; it != end; ++it) { Node* n = *it; StyleSheet* sheet = 0; if (n->nodeType() == Node::PROCESSING_INSTRUCTION_NODE) { // Processing instruction (XML documents only). // We don't support linking to embedded CSS stylesheets, see <https://bugs.webkit.org/show_bug.cgi?id=49281> for discussion. ProcessingInstruction* pi = static_cast<ProcessingInstruction*>(n); sheet = pi->sheet(); #if ENABLE(XSLT) // Don't apply XSL transforms to already transformed documents -- <rdar://problem/4132806> if (pi->isXSL() && !m_document->transformSourceDocument()) { // Don't apply XSL transforms until loading is finished. if (!m_document->parsing()) m_document->applyXSLTransform(pi); return; } #endif } else if ((n->isHTMLElement() && (n->hasTagName(linkTag) || n->hasTagName(styleTag))) #if ENABLE(SVG) || (n->isSVGElement() && n->hasTagName(SVGNames::styleTag)) #endif ) { Element* e = static_cast<Element*>(n); AtomicString title = e->getAttribute(titleAttr); bool enabledViaScript = false; if (e->hasLocalName(linkTag)) { // <LINK> element HTMLLinkElement* linkElement = static_cast<HTMLLinkElement*>(n); if (linkElement->isDisabled()) continue; enabledViaScript = linkElement->isEnabledViaScript(); if (linkElement->styleSheetIsLoading()) { // it is loading but we should still decide which style sheet set to use if (!enabledViaScript && !title.isEmpty() && m_preferredStylesheetSetName.isEmpty()) { const AtomicString& rel = e->getAttribute(relAttr); if (!rel.contains("alternate")) { m_preferredStylesheetSetName = title; m_selectedStylesheetSetName = title; } } continue; } if (!linkElement->sheet()) title = nullAtom; } // Get the current preferred styleset. This is the // set of sheets that will be enabled. #if ENABLE(SVG) if (n->isSVGElement() && n->hasTagName(SVGNames::styleTag)) sheet = static_cast<SVGStyleElement*>(n)->sheet(); else #endif if (e->hasLocalName(linkTag)) sheet = static_cast<HTMLLinkElement*>(n)->sheet(); else // <STYLE> element sheet = static_cast<HTMLStyleElement*>(n)->sheet(); // Check to see if this sheet belongs to a styleset // (thus making it PREFERRED or ALTERNATE rather than // PERSISTENT). AtomicString rel = e->getAttribute(relAttr); if (!enabledViaScript && !title.isEmpty()) { // Yes, we have a title. if (m_preferredStylesheetSetName.isEmpty()) { // No preferred set has been established. If // we are NOT an alternate sheet, then establish // us as the preferred set. Otherwise, just ignore // this sheet. if (e->hasLocalName(styleTag) || !rel.contains("alternate")) m_preferredStylesheetSetName = m_selectedStylesheetSetName = title; } if (title != m_preferredStylesheetSetName) sheet = 0; } if (rel.contains("alternate") && title.isEmpty()) sheet = 0; } if (sheet) sheets.append(sheet); } }
static bool matchesReservedStringEmail(const AtomicString& string) { return string.contains("email", false /* caseSensitive */); }
void MediaSource::streamEndedWithError(const AtomicString& error, ExceptionCode& ec) { DEPRECATED_DEFINE_STATIC_LOCAL(const AtomicString, network, ("network", AtomicString::ConstructFromLiteral)); DEPRECATED_DEFINE_STATIC_LOCAL(const AtomicString, decode, ("decode", AtomicString::ConstructFromLiteral)); LOG(MediaSource, "MediaSource::streamEndedWithError(%p) : %s", this, error.string().ascii().data()); // 2.4.7 https://dvcs.w3.org/hg/html-media/raw-file/tip/media-source/media-source.html#end-of-stream-algorithm // 3. if (error.isEmpty()) { // ↳ If error is not set, is null, or is an empty string // 1. Run the duration change algorithm with new duration set to the highest end time reported by // the buffered attribute across all SourceBuffer objects in sourceBuffers. MediaTime maxEndTime; for (auto& sourceBuffer : *m_sourceBuffers) { if (auto length = sourceBuffer->buffered()->length()) maxEndTime = std::max(sourceBuffer->buffered()->ranges().end(length - 1), maxEndTime); } setDurationInternal(maxEndTime); // 2. Notify the media element that it now has all of the media data. m_private->markEndOfStream(MediaSourcePrivate::EosNoError); } // NOTE: Do steps 1 & 2 after step 3 (with an empty error) to avoid the MediaSource's readyState being re-opened by a // remove() operation resulting from a duration change. // FIXME: Re-number or update this section once <https://www.w3.org/Bugs/Public/show_bug.cgi?id=26316> is resolved. // 1. Change the readyState attribute value to "ended". // 2. Queue a task to fire a simple event named sourceended at the MediaSource. setReadyState(endedKeyword()); if (error == network) { // ↳ If error is set to "network" ASSERT(m_mediaElement); if (m_mediaElement->readyState() == HTMLMediaElement::HAVE_NOTHING) { // ↳ If the HTMLMediaElement.readyState attribute equals HAVE_NOTHING // Run the "If the media data cannot be fetched at all, due to network errors, causing // the user agent to give up trying to fetch the resource" steps of the resource fetch algorithm. // NOTE: This step is handled by HTMLMediaElement::mediaLoadingFailed(). m_mediaElement->mediaLoadingFailed(MediaPlayer::NetworkError); } else { // ↳ If the HTMLMediaElement.readyState attribute is greater than HAVE_NOTHING // Run the "If the connection is interrupted after some media data has been received, causing the // user agent to give up trying to fetch the resource" steps of the resource fetch algorithm. // NOTE: This step is handled by HTMLMediaElement::mediaLoadingFailedFatally(). m_mediaElement->mediaLoadingFailedFatally(MediaPlayer::NetworkError); } } else if (error == decode) { // ↳ If error is set to "decode" ASSERT(m_mediaElement); if (m_mediaElement->readyState() == HTMLMediaElement::HAVE_NOTHING) { // ↳ If the HTMLMediaElement.readyState attribute equals HAVE_NOTHING // Run the "If the media data can be fetched but is found by inspection to be in an unsupported // format, or can otherwise not be rendered at all" steps of the resource fetch algorithm. // NOTE: This step is handled by HTMLMediaElement::mediaLoadingFailed(). m_mediaElement->mediaLoadingFailed(MediaPlayer::FormatError); } else { // ↳ If the HTMLMediaElement.readyState attribute is greater than HAVE_NOTHING // Run the media data is corrupted steps of the resource fetch algorithm. // NOTE: This step is handled by HTMLMediaElement::mediaLoadingFailedFatally(). m_mediaElement->mediaLoadingFailedFatally(MediaPlayer::DecodeError); } } else if (!error.isEmpty()) { // ↳ Otherwise // Throw an INVALID_ACCESS_ERR exception. ec = INVALID_ACCESS_ERR; } }
static void resolveKeyframes(StyleResolver* resolver, Element* element, const RenderStyle& style, const AtomicString& name, TimingFunction* defaultTimingFunction, Vector<std::pair<KeyframeAnimationEffect::KeyframeVector, RefPtr<TimingFunction> > >& keyframesAndTimingFunctions) { ASSERT(RuntimeEnabledFeatures::webAnimationsCSSEnabled()); const StyleRuleKeyframes* keyframesRule = CSSAnimations::matchScopedKeyframesRule(resolver, element, name.impl()); if (!keyframesRule) return; const Vector<RefPtr<StyleKeyframe> >& styleKeyframes = keyframesRule->keyframes(); if (styleKeyframes.isEmpty()) return; // Construct and populate the style for each keyframe PropertySet specifiedProperties; KeyframeAnimationEffect::KeyframeVector keyframes; HashMap<double, RefPtr<TimingFunction> > perKeyframeTimingFunctions; for (size_t i = 0; i < styleKeyframes.size(); ++i) { const StyleKeyframe* styleKeyframe = styleKeyframes[i].get(); RefPtr<RenderStyle> keyframeStyle = resolver->styleForKeyframe(element, style, styleKeyframe, name); RefPtr<Keyframe> keyframe = Keyframe::create(); const Vector<double>& offsets = styleKeyframe->keys(); ASSERT(!offsets.isEmpty()); keyframe->setOffset(offsets[0]); TimingFunction* timingFunction = defaultTimingFunction; const StylePropertySet* properties = styleKeyframe->properties(); for (unsigned j = 0; j < properties->propertyCount(); j++) { CSSPropertyID property = properties->propertyAt(j).id(); specifiedProperties.add(property); if (property == CSSPropertyWebkitAnimationTimingFunction || property == CSSPropertyAnimationTimingFunction) timingFunction = KeyframeValue::timingFunction(*keyframeStyle); else if (CSSAnimations::isAnimatableProperty(property)) keyframe->setPropertyValue(property, CSSAnimatableValueFactory::create(property, *keyframeStyle).get()); } keyframes.append(keyframe); // The last keyframe specified at a given offset is used. perKeyframeTimingFunctions.set(offsets[0], timingFunction); for (size_t j = 1; j < offsets.size(); ++j) { keyframes.append(keyframe->cloneWithOffset(offsets[j])); perKeyframeTimingFunctions.set(offsets[j], timingFunction); } } ASSERT(!keyframes.isEmpty()); if (!perKeyframeTimingFunctions.contains(0)) perKeyframeTimingFunctions.set(0, defaultTimingFunction); for (PropertySet::const_iterator iter = specifiedProperties.begin(); iter != specifiedProperties.end(); ++iter) { const CSSPropertyID property = *iter; ASSERT(property != CSSPropertyInvalid); blink::Platform::current()->histogramSparse("WebCore.Animation.CSSProperties", UseCounter::mapCSSPropertyIdToCSSSampleIdForHistogram(property)); } // Remove duplicate keyframes. In CSS the last keyframe at a given offset takes priority. std::stable_sort(keyframes.begin(), keyframes.end(), Keyframe::compareOffsets); size_t targetIndex = 0; for (size_t i = 1; i < keyframes.size(); i++) { if (keyframes[i]->offset() != keyframes[targetIndex]->offset()) targetIndex++; if (targetIndex != i) keyframes[targetIndex] = keyframes[i]; } keyframes.shrink(targetIndex + 1); // Add 0% and 100% keyframes if absent. RefPtr<Keyframe> startKeyframe = keyframes[0]; if (startKeyframe->offset()) { startKeyframe = Keyframe::create(); startKeyframe->setOffset(0); keyframes.prepend(startKeyframe); } RefPtr<Keyframe> endKeyframe = keyframes[keyframes.size() - 1]; if (endKeyframe->offset() != 1) { endKeyframe = Keyframe::create(); endKeyframe->setOffset(1); keyframes.append(endKeyframe); } ASSERT(keyframes.size() >= 2); ASSERT(!keyframes.first()->offset()); ASSERT(keyframes.last()->offset() == 1); // Snapshot current property values for 0% and 100% if missing. PropertySet allProperties; size_t numKeyframes = keyframes.size(); for (size_t i = 0; i < numKeyframes; i++) { const PropertySet& keyframeProperties = keyframes[i]->properties(); for (PropertySet::const_iterator iter = keyframeProperties.begin(); iter != keyframeProperties.end(); ++iter) allProperties.add(*iter); } const PropertySet& startKeyframeProperties = startKeyframe->properties(); const PropertySet& endKeyframeProperties = endKeyframe->properties(); bool missingStartValues = startKeyframeProperties.size() < allProperties.size(); bool missingEndValues = endKeyframeProperties.size() < allProperties.size(); if (missingStartValues || missingEndValues) { for (PropertySet::const_iterator iter = allProperties.begin(); iter != allProperties.end(); ++iter) { const CSSPropertyID property = *iter; bool startNeedsValue = missingStartValues && !startKeyframeProperties.contains(property); bool endNeedsValue = missingEndValues && !endKeyframeProperties.contains(property); if (!startNeedsValue && !endNeedsValue) continue; RefPtr<AnimatableValue> snapshotValue = CSSAnimatableValueFactory::create(property, style); if (startNeedsValue) startKeyframe->setPropertyValue(property, snapshotValue.get()); if (endNeedsValue) endKeyframe->setPropertyValue(property, snapshotValue.get()); } } ASSERT(startKeyframe->properties().size() == allProperties.size()); ASSERT(endKeyframe->properties().size() == allProperties.size()); // Determine how many keyframes specify each property. Note that this must // be done after we've filled in end keyframes. typedef HashCountedSet<CSSPropertyID> PropertyCountedSet; PropertyCountedSet propertyCounts; for (size_t i = 0; i < numKeyframes; ++i) { const PropertySet& properties = keyframes[i]->properties(); for (PropertySet::const_iterator iter = properties.begin(); iter != properties.end(); ++iter) propertyCounts.add(*iter); } // Split keyframes into groups, where each group contains only keyframes // which specify all properties used in that group. Each group is animated // in a separate animation, to allow per-keyframe timing functions to be // applied correctly. for (PropertyCountedSet::const_iterator iter = propertyCounts.begin(); iter != propertyCounts.end(); ++iter) { const CSSPropertyID property = iter->key; const size_t count = iter->value; ASSERT(count <= numKeyframes); if (count == numKeyframes) continue; KeyframeAnimationEffect::KeyframeVector splitOutKeyframes; for (size_t i = 0; i < numKeyframes; i++) { Keyframe* keyframe = keyframes[i].get(); if (!keyframe->properties().contains(property)) { ASSERT(i && i != numKeyframes - 1); continue; } RefPtr<Keyframe> clonedKeyframe = Keyframe::create(); clonedKeyframe->setOffset(keyframe->offset()); clonedKeyframe->setComposite(keyframe->composite()); clonedKeyframe->setPropertyValue(property, keyframe->propertyValue(property)); splitOutKeyframes.append(clonedKeyframe); // Note that it's OK if this keyframe ends up having no // properties. This can only happen when none of the properties // are specified in all keyframes, in which case we won't animate // anything with these keyframes. keyframe->clearPropertyValue(property); } ASSERT(!splitOutKeyframes.first()->offset()); ASSERT(splitOutKeyframes.last()->offset() == 1); #ifndef NDEBUG for (size_t j = 0; j < splitOutKeyframes.size(); ++j) ASSERT(splitOutKeyframes[j]->properties().size() == 1); #endif keyframesAndTimingFunctions.append(std::make_pair(splitOutKeyframes, generateTimingFunction(splitOutKeyframes, perKeyframeTimingFunctions))); } unsigned numPropertiesSpecifiedInAllKeyframes = keyframes.first()->properties().size(); #ifndef NDEBUG for (size_t i = 1; i < numKeyframes; ++i) ASSERT(keyframes[i]->properties().size() == numPropertiesSpecifiedInAllKeyframes); #endif // If the animation specifies any keyframes, we always provide at least one // vector of resolved keyframes, even if no properties are animated. if (numPropertiesSpecifiedInAllKeyframes || keyframesAndTimingFunctions.isEmpty()) keyframesAndTimingFunctions.append(std::make_pair(keyframes, generateTimingFunction(keyframes, perKeyframeTimingFunctions))); }
static bool attributeValueMatches(const Attribute& attribute, CSSSelector::Match match, const AtomicString& selectorValue, bool caseSensitive) { const AtomicString& value = attribute.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; }
void ImageLoader::updateFromElement() { // If we're not making renderers for the page, then don't load images. We don't want to slow // down the raw HTML parsing case by loading images we don't intend to display. Document& document = m_element->document(); if (!document.hasLivingRenderTree()) return; AtomicString attr = m_element->imageSourceURL(); if (attr == m_failedLoadURL) return; // Do not load any image if the 'src' attribute is missing or if it is // an empty string. CachedResourceHandle<CachedImage> newImage = 0; if (!attr.isNull() && !stripLeadingAndTrailingHTMLSpaces(attr).isEmpty()) { CachedResourceRequest request(ResourceRequest(document.completeURL(sourceURI(attr)))); request.setInitiator(element()); String crossOriginMode = m_element->fastGetAttribute(HTMLNames::crossoriginAttr); if (!crossOriginMode.isNull()) { StoredCredentials allowCredentials = equalIgnoringCase(crossOriginMode, "use-credentials") ? AllowStoredCredentials : DoNotAllowStoredCredentials; updateRequestForAccessControl(request.mutableResourceRequest(), document.securityOrigin(), allowCredentials); } if (m_loadManually) { bool autoLoadOtherImages = document.cachedResourceLoader()->autoLoadImages(); document.cachedResourceLoader()->setAutoLoadImages(false); newImage = new CachedImage(request.resourceRequest()); newImage->setLoading(true); newImage->setOwningCachedResourceLoader(document.cachedResourceLoader()); document.cachedResourceLoader()->m_documentResources.set(newImage->url(), newImage.get()); document.cachedResourceLoader()->setAutoLoadImages(autoLoadOtherImages); } else newImage = document.cachedResourceLoader()->requestImage(request); // If we do not have an image here, it means that a cross-site // violation occurred, or that the image was blocked via Content // Security Policy, or the page is being dismissed. Trigger an // error event if the page is not being dismissed. if (!newImage && !pageIsBeingDismissed(document)) { m_failedLoadURL = attr; m_hasPendingErrorEvent = true; errorEventSender().dispatchEventSoon(this); } else clearFailedLoadURL(); } else if (!attr.isNull()) { // Fire an error event if the url is empty. // FIXME: Should we fire this event asynchronoulsy via errorEventSender()? m_element->dispatchEvent(Event::create(eventNames().errorEvent, false, false)); } CachedImage* oldImage = m_image.get(); if (newImage != oldImage) { if (m_hasPendingBeforeLoadEvent) { beforeLoadEventSender().cancelEvent(this); m_hasPendingBeforeLoadEvent = false; } if (m_hasPendingLoadEvent) { loadEventSender().cancelEvent(this); m_hasPendingLoadEvent = false; } // Cancel error events that belong to the previous load, which is now cancelled by changing the src attribute. // If newImage is null and m_hasPendingErrorEvent is true, we know the error event has been just posted by // this load and we should not cancel the event. // FIXME: If both previous load and this one got blocked with an error, we can receive one error event instead of two. if (m_hasPendingErrorEvent && newImage) { errorEventSender().cancelEvent(this); m_hasPendingErrorEvent = false; } m_image = newImage; m_hasPendingBeforeLoadEvent = !document.isImageDocument() && newImage; m_hasPendingLoadEvent = newImage; m_imageComplete = !newImage; if (newImage) { if (!document.isImageDocument()) { if (!document.hasListenerType(Document::BEFORELOAD_LISTENER)) dispatchPendingBeforeLoadEvent(); else beforeLoadEventSender().dispatchEventSoon(this); } else updateRenderer(); // If newImage is cached, addClient() will result in the load event // being queued to fire. Ensure this happens after beforeload is // dispatched. newImage->addClient(this); } if (oldImage) oldImage->removeClient(this); } if (RenderImageResource* imageResource = renderImageResource()) imageResource->resetAnimation(); // Only consider updating the protection ref-count of the Element immediately before returning // from this function as doing so might result in the destruction of this ImageLoader. updatedHasPendingEvent(); }
String DOMTokenList::removeToken(const AtomicString& input, const AtomicString& token) { Vector<String> tokens; tokens.append(token.string()); return removeTokens(input, tokens); }
void XMLDocumentParser::startElementNs(const xmlChar* xmlLocalName, const xmlChar* xmlPrefix, const xmlChar* xmlURI, int nb_namespaces, const xmlChar** libxmlNamespaces, int nb_attributes, int nb_defaulted, const xmlChar** libxmlAttributes) { if (isStopped()) return; if (m_parserPaused) { m_pendingCallbacks->appendStartElementNSCallback(xmlLocalName, xmlPrefix, xmlURI, nb_namespaces, libxmlNamespaces, nb_attributes, nb_defaulted, libxmlAttributes); return; } exitText(); AtomicString localName = toAtomicString(xmlLocalName); AtomicString uri = toAtomicString(xmlURI); AtomicString prefix = toAtomicString(xmlPrefix); if (m_parsingFragment && uri.isNull()) { if (!prefix.isNull()) uri = m_prefixToNamespaceMap.get(prefix); else uri = m_defaultNamespaceURI; } // If libxml entity parsing is broken, transfer the currentNodes' namespaceURI to the new node, // if we're currently expanding elements which originate from an entity declaration. if (hackAroundLibXMLEntityParsingBug() && depthTriggeringEntityExpansion() != -1 && context()->depth > depthTriggeringEntityExpansion() && uri.isNull() && prefix.isNull()) uri = m_currentNode->namespaceURI(); bool isFirstElement = !m_sawFirstElement; m_sawFirstElement = true; QualifiedName qName(prefix, localName, uri); RefPtr<Element> newElement = document()->createElement(qName, true); if (!newElement) { stopParsing(); return; } Vector<Attribute, 8> prefixedAttributes; ExceptionCode ec = 0; handleNamespaceAttributes(prefixedAttributes, libxmlNamespaces, nb_namespaces, ec); if (ec) { newElement->parserSetAttributes(prefixedAttributes, m_scriptingPermission); stopParsing(); return; } handleElementAttributes(prefixedAttributes, libxmlAttributes, nb_attributes, ec); newElement->parserSetAttributes(prefixedAttributes, m_scriptingPermission); if (ec) { stopParsing(); return; } newElement->beginParsingChildren(); ScriptElement* scriptElement = toScriptElement(newElement.get()); if (scriptElement) m_scriptStartPosition = textPosition(); m_currentNode->parserAppendChild(newElement.get()); pushCurrentNode(newElement.get()); if (m_view && !newElement->attached()) newElement->attach(); if (newElement->hasTagName(HTMLNames::htmlTag)) static_cast<HTMLHtmlElement*>(newElement.get())->insertedByParser(); if (!m_parsingFragment && isFirstElement && document()->frame()) document()->frame()->loader()->dispatchDocumentElementAvailable(); }
void DocumentStyleSheetCollection::collectActiveStyleSheets(Vector<RefPtr<StyleSheet>>& sheets) { if (m_document.settings() && !m_document.settings()->authorAndUserStylesEnabled()) return; for (auto& node : m_styleSheetCandidateNodes) { StyleSheet* sheet = nullptr; if (node->nodeType() == Node::PROCESSING_INSTRUCTION_NODE) { // Processing instruction (XML documents only). // We don't support linking to embedded CSS stylesheets, see <https://bugs.webkit.org/show_bug.cgi?id=49281> for discussion. ProcessingInstruction* pi = toProcessingInstruction(node); sheet = pi->sheet(); #if ENABLE(XSLT) // Don't apply XSL transforms to already transformed documents -- <rdar://problem/4132806> if (pi->isXSL() && !m_document.transformSourceDocument()) { // Don't apply XSL transforms until loading is finished. if (!m_document.parsing()) m_document.applyXSLTransform(pi); return; } #endif } else if ((node->isHTMLElement() && (toHTMLElement(*node).hasTagName(linkTag) || toHTMLElement(*node).hasTagName(styleTag))) || (node->isSVGElement() && toSVGElement(*node).hasTagName(SVGNames::styleTag))) { Element& element = toElement(*node); AtomicString title = element.fastGetAttribute(titleAttr); bool enabledViaScript = false; if (isHTMLLinkElement(element)) { // <LINK> element HTMLLinkElement& linkElement = toHTMLLinkElement(element); if (linkElement.isDisabled()) continue; enabledViaScript = linkElement.isEnabledViaScript(); if (linkElement.styleSheetIsLoading()) { // it is loading but we should still decide which style sheet set to use if (!enabledViaScript && !title.isEmpty() && m_preferredStylesheetSetName.isEmpty()) { if (!linkElement.fastGetAttribute(relAttr).contains("alternate")) { m_preferredStylesheetSetName = title; m_selectedStylesheetSetName = title; } } continue; } if (!linkElement.sheet()) title = nullAtom; } // Get the current preferred styleset. This is the // set of sheets that will be enabled. if (isSVGStyleElement(element)) sheet = toSVGStyleElement(element).sheet(); else if (isHTMLLinkElement(element)) sheet = toHTMLLinkElement(element).sheet(); else sheet = toHTMLStyleElement(element).sheet(); // Check to see if this sheet belongs to a styleset // (thus making it PREFERRED or ALTERNATE rather than // PERSISTENT). auto& rel = element.fastGetAttribute(relAttr); if (!enabledViaScript && !title.isEmpty()) { // Yes, we have a title. if (m_preferredStylesheetSetName.isEmpty()) { // No preferred set has been established. If // we are NOT an alternate sheet, then establish // us as the preferred set. Otherwise, just ignore // this sheet. if (isHTMLStyleElement(element) || !rel.contains("alternate")) m_preferredStylesheetSetName = m_selectedStylesheetSetName = title; } if (title != m_preferredStylesheetSetName) sheet = nullptr; } if (rel.contains("alternate") && title.isEmpty()) sheet = nullptr; } if (sheet) sheets.append(sheet); } }
FontPlatformData::FontPlatformData(const FontDescription& fontDescription, const AtomicString& familyName) : m_context(0) , m_font(0) , m_size(fontDescription.computedSize()) , m_syntheticBold(false) , m_syntheticOblique(false) , m_scaledFont(0) { FontPlatformData::init(); CString stored_family = familyName.string().utf8(); char const* families[] = { stored_family.data(), NULL }; switch (fontDescription.genericFamily()) { case FontDescription::SerifFamily: families[1] = "serif"; break; case FontDescription::SansSerifFamily: families[1] = "sans"; break; case FontDescription::MonospaceFamily: families[1] = "monospace"; break; case FontDescription::NoFamily: case FontDescription::StandardFamily: default: families[1] = "sans"; break; } PangoFontDescription* description = pango_font_description_new(); pango_font_description_set_absolute_size(description, fontDescription.computedSize() * PANGO_SCALE); // FIXME: Map all FontWeight values to Pango font weights. if (fontDescription.weight() >= FontWeight600) pango_font_description_set_weight(description, PANGO_WEIGHT_BOLD); if (fontDescription.italic()) pango_font_description_set_style(description, PANGO_STYLE_ITALIC); #if PANGO_VERSION_CHECK(1,21,5) // deprecated in 1.21 int version = pango_version(); if (version > 12105 ) m_context = pango_font_map_create_context(m_fontMap); else m_context = pango_cairo_font_map_create_context(PANGO_CAIRO_FONT_MAP(m_fontMap)); #else m_context = pango_cairo_font_map_create_context(PANGO_CAIRO_FONT_MAP(m_fontMap)); #endif for (unsigned int i = 0; !m_font && i < G_N_ELEMENTS(families); i++) { pango_font_description_set_family(description, families[i]); pango_context_set_font_description(m_context, description); m_font = pango_font_map_load_font(m_fontMap, m_context, description); } #if PANGO_VERSION_CHECK(1,18,0) if (m_font) m_scaledFont = cairo_scaled_font_reference(pango_cairo_font_get_scaled_font(PANGO_CAIRO_FONT(m_font))); #else // This compatibility code for older versions of Pango is not well-tested. if (m_font) { PangoFcFont* fcfont = PANGO_FC_FONT(m_font); cairo_font_face_t* face = cairo_ft_font_face_create_for_pattern(fcfont->font_pattern); double size; if (FcPatternGetDouble(fcfont->font_pattern, FC_PIXEL_SIZE, 0, &size) != FcResultMatch) size = 12.0; cairo_matrix_t fontMatrix; cairo_matrix_init_scale(&fontMatrix, size, size); cairo_font_options_t* fontOptions; if (pango_cairo_context_get_font_options(m_context)) fontOptions = cairo_font_options_copy(pango_cairo_context_get_font_options(m_context)); else fontOptions = cairo_font_options_create(); cairo_matrix_t ctm; cairo_matrix_init_identity(&ctm); m_scaledFont = cairo_scaled_font_create(face, &fontMatrix, &ctm, fontOptions); cairo_font_options_destroy(fontOptions); cairo_font_face_destroy(face); } #endif pango_font_description_free(description); }
void TreeScope::removeLabel(const AtomicString& forAttributeValue, HTMLLabelElement* element) { ASSERT(m_labelsByForAttribute); m_labelsByForAttribute->remove(forAttributeValue.impl(), element); }
JSValuePtr windowProtoFuncOpen(ExecState* exec, JSObject*, JSValuePtr thisValue, const ArgList& args) { JSDOMWindow* window = toJSDOMWindow(thisValue); if (!window) return throwError(exec, TypeError); if (!window->allowsAccessFrom(exec)) return jsUndefined(); Frame* frame = window->impl()->frame(); if (!frame) return jsUndefined(); Frame* activeFrame = asJSDOMWindow(exec->dynamicGlobalObject())->impl()->frame(); if (!activeFrame) return jsUndefined(); Page* page = frame->page(); String urlString = valueToStringWithUndefinedOrNullCheck(exec, args.at(exec, 0)); AtomicString frameName = args.at(exec, 1)->isUndefinedOrNull() ? "_blank" : AtomicString(args.at(exec, 1)->toString(exec)); // Because FrameTree::find() returns true for empty strings, we must check for empty framenames. // Otherwise, illegitimate window.open() calls with no name will pass right through the popup blocker. if (!allowPopUp(exec) && (frameName.isEmpty() || !frame->tree()->find(frameName))) return jsUndefined(); // Get the target frame for the special cases of _top and _parent. In those // cases, we can schedule a location change right now and return early. bool topOrParent = false; if (frameName == "_top") { frame = frame->tree()->top(); topOrParent = true; } else if (frameName == "_parent") { if (Frame* parent = frame->tree()->parent()) frame = parent; topOrParent = true; } if (topOrParent) { if (!activeFrame->loader()->shouldAllowNavigation(frame)) return jsUndefined(); String completedURL; if (!urlString.isEmpty()) completedURL = activeFrame->document()->completeURL(urlString).string(); const JSDOMWindow* targetedWindow = toJSDOMWindow(frame); if (!completedURL.isEmpty() && (!protocolIs(completedURL, "javascript") || (targetedWindow && targetedWindow->allowsAccessFrom(exec)))) { bool userGesture = activeFrame->script()->processingUserGesture(); frame->loader()->scheduleLocationChange(completedURL, activeFrame->loader()->outgoingReferrer(), false, userGesture); } return toJS(exec, frame->domWindow()); } // In the case of a named frame or a new window, we'll use the createWindow() helper WindowFeatures windowFeatures(valueToStringWithUndefinedOrNullCheck(exec, args.at(exec, 2))); FloatRect windowRect(windowFeatures.xSet ? windowFeatures.x : 0, windowFeatures.ySet ? windowFeatures.y : 0, windowFeatures.widthSet ? windowFeatures.width : 0, windowFeatures.heightSet ? windowFeatures.height : 0); DOMWindow::adjustWindowRect(screenAvailableRect(page ? page->mainFrame()->view() : 0), windowRect, windowRect); windowFeatures.x = windowRect.x(); windowFeatures.y = windowRect.y(); windowFeatures.height = windowRect.height(); windowFeatures.width = windowRect.width(); frame = createWindow(exec, frame, urlString, frameName, windowFeatures, noValue()); if (!frame) return jsUndefined(); return toJS(exec, frame->domWindow()); // global object }