AXObject* AXTableColumn::headerObjectForSection(RenderTableSection* section, bool thTagRequired) { if (!section) return 0; unsigned numCols = section->numColumns(); if (m_columnIndex >= numCols) return 0; if (!section->numRows()) return 0; RenderTableCell* cell = 0; // also account for cells that have a span for (int testCol = m_columnIndex; testCol >= 0; --testCol) { RenderTableCell* testCell = section->primaryCellAt(0, testCol); if (!testCell) continue; // we've reached a cell that doesn't even overlap our column // it can't be our header if ((testCell->col() + (testCell->colSpan()-1)) < m_columnIndex) break; Node* node = testCell->node(); if (!node) continue; if (thTagRequired && !node->hasTagName(thTag)) continue; cell = testCell; } if (!cell) return 0; return axObjectCache()->getOrCreate(cell); }
Element *HTMLLegendElement::formElement() { // Check if there's a fieldset belonging to this legend. Node *fieldset = parentNode(); while (fieldset && !fieldset->hasTagName(fieldsetTag)) fieldset = fieldset->parentNode(); if (!fieldset) return 0; // Find first form element inside the fieldset. // FIXME: Should we care about tabindex? Node *node = fieldset; while ((node = node->traverseNextNode(fieldset))) { if (node->isHTMLElement()) { HTMLElement *element = static_cast<HTMLElement *>(node); if (!element->hasLocalName(legendTag) && element->isFormControlElement()) return element; } } return 0; }
void StyleInvalidationAnalysis::analyzeStyleSheet(StyleSheetContents* styleSheetContents) { ASSERT(!styleSheetContents->isLoading()); // See if all rules on the sheet are scoped to some specific ids or classes. // Then test if we actually have any of those in the tree at the moment. const Vector<RefPtr<StyleRuleImport> >& importRules = styleSheetContents->importRules(); for (unsigned i = 0; i < importRules.size(); ++i) { if (!importRules[i]->styleSheet()) continue; analyzeStyleSheet(importRules[i]->styleSheet()); if (m_dirtiesAllStyle) return; } if (styleSheetContents->hasSingleOwnerNode()) { Node* ownerNode = styleSheetContents->singleOwnerNode(); if (ownerNode && ownerNode->hasTagName(HTMLNames::styleTag) && toHTMLStyleElement(ownerNode)->isRegisteredAsScoped()) { m_scopingNodes.append(determineScopingNodeForStyleScoped(toHTMLStyleElement(ownerNode), styleSheetContents)); return; } } const Vector<RefPtr<StyleRuleBase> >& rules = styleSheetContents->childRules(); for (unsigned i = 0; i < rules.size(); i++) { StyleRuleBase* rule = rules[i].get(); if (!rule->isStyleRule()) { if (ruleAdditionMightRequireDocumentStyleRecalc(rule)) { m_dirtiesAllStyle = true; return; } continue; } StyleRule* styleRule = toStyleRule(rule); if (!determineSelectorScopes(styleRule->selectorList(), m_idScopes, m_classScopes)) { m_dirtiesAllStyle = true; return; } } }
unsigned HTMLTextFormControlElement::indexForPosition(const Position& passedPosition) const { TextControlInnerTextElement* innerText = innerTextElement(); if (!innerText || !innerText->contains(passedPosition.anchorNode()) || passedPosition.isNull()) return 0; if (positionBeforeNode(innerText) == passedPosition) return 0; unsigned index = 0; Node* startNode = passedPosition.computeNodeBeforePosition(); if (!startNode) startNode = passedPosition.containerNode(); ASSERT(startNode); ASSERT(innerText->contains(startNode)); for (Node* node = startNode; node; node = NodeTraversal::previous(node, innerText)) { if (node->isTextNode()) { unsigned length = toText(*node).length(); if (node == passedPosition.containerNode()) index += std::min<unsigned>(length, passedPosition.offsetInContainerNode()); else index += length; } else if (node->hasTagName(brTag)) index++; } unsigned length = innerTextValue().length(); index = std::min(index, length); // FIXME: We shouldn't have to call innerTextValue() just to ignore the last LF. See finishText. #ifndef ASSERT_DISABLED VisiblePosition visiblePosition = passedPosition; unsigned indexComputedByVisiblePosition = 0; if (visiblePosition.isNotNull()) indexComputedByVisiblePosition = WebCore::indexForVisiblePosition(innerText, visiblePosition, false /* forSelectionPreservation */); ASSERT(index == indexComputedByVisiblePosition); #endif return index; }
String AccessibilityTable::title() const { if (!isAccessibilityTable()) return AccessibilityRenderObject::title(); String title; if (!m_renderer) return title; // see if there is a caption Node* tableElement = m_renderer->node(); if (tableElement && tableElement->hasTagName(tableTag)) { HTMLTableCaptionElement* caption = static_cast<HTMLTableElement*>(tableElement)->caption(); if (caption) title = caption->innerText(); } // try the standard if (title.isEmpty()) title = AccessibilityRenderObject::title(); return title; }
bool AccessibilityTable::isTableExposableThroughAccessibility() const { // The following is a heuristic used to determine if a // <table> should be exposed as an AXTable. The goal // is to only show "data" tables. if (!m_renderer) return false; // If the developer assigned an aria role to this, then we // shouldn't expose it as a table, unless, of course, the aria // role is a table. if (hasARIARole()) return false; // Gtk+ ATs expect all tables to be exposed as tables. #if PLATFORM(GTK) Node* tableNode = toRenderTable(m_renderer)->node(); return tableNode && tableNode->hasTagName(tableTag); #endif return isDataTable(); }
void HTMLFrameSetElement::attach() { // Inherit default settings from parent frameset // FIXME: This is not dynamic. for (Node* node = parentNode(); node; node = node->parentNode()) { if (node->hasTagName(framesetTag)) { HTMLFrameSetElement* frameset = static_cast<HTMLFrameSetElement*>(node); if (!frameBorderSet) frameborder = frameset->hasFrameBorder(); if (frameborder) { if (!m_borderSet) m_border = frameset->border(); if (!m_borderColorSet) m_borderColorSet = frameset->hasBorderColor(); } if (!noresize) noresize = frameset->noResize(); break; } } HTMLElement::attach(); }
JSValue JSHTMLDocument::nameGetter(ExecState* exec, JSValue slotBase, PropertyName propertyName) { JSHTMLDocument* thisObj = jsCast<JSHTMLDocument*>(asObject(slotBase)); HTMLDocument* document = toHTMLDocument(thisObj->impl()); AtomicStringImpl* atomicPropertyName = findAtomicString(propertyName); if (!atomicPropertyName || !document->documentNamedItemMap().contains(atomicPropertyName)) return jsUndefined(); if (UNLIKELY(!document->documentNamedItemMap().containsSingle(atomicPropertyName))) { RefPtr<HTMLCollection> collection = document->documentNamedItems(atomicPropertyName); ASSERT(!collection->isEmpty()); ASSERT(!collection->hasExactlyOneItem()); return toJS(exec, thisObj->globalObject(), WTF::getPtr(collection)); } Node* node = document->documentNamedItemMap().getElementByDocumentNamedItem(atomicPropertyName, document); Frame* frame; if (node->hasTagName(iframeTag) && (frame = static_cast<HTMLIFrameElement*>(node)->contentFrame())) return toJS(exec, frame); return toJS(exec, thisObj->globalObject(), node); }
void HTMLEmbedElement::insertedIntoDocument() { HTMLPlugInImageElement::insertedIntoDocument(); if (!inDocument()) return; if (document()->isHTMLDocument()) static_cast<HTMLDocument*>(document())->addNamedItem(m_name); String width = getAttribute(widthAttr); String height = getAttribute(heightAttr); if (!width.isEmpty() || !height.isEmpty()) { Node* n = parentNode(); while (n && !n->hasTagName(objectTag)) n = n->parentNode(); if (n) { if (!width.isEmpty()) static_cast<HTMLObjectElement*>(n)->setAttribute(widthAttr, width); if (!height.isEmpty()) static_cast<HTMLObjectElement*>(n)->setAttribute(heightAttr, height); } } }
bool SVGAltGlyphItemElement::hasValidGlyphElements(Vector<String>& glyphNames) const { // Spec: http://www.w3.org/TR/SVG/text.html#AltGlyphItemElement // The ‘altGlyphItem’ element defines a candidate set of possible glyph substitutions. // The first ‘altGlyphItem’ element whose referenced glyphs are all available is chosen. // Its glyphs are rendered instead of the character(s) that are inside of the referencing // ‘altGlyph’ element. // // Here we fill glyphNames and return true only if all referenced glyphs are valid and // there is at least one glyph. for (Node* child = firstChild(); child; child = child->nextSibling()) { if (child->hasTagName(SVGNames::glyphRefTag)) { String referredGlyphName; if (toSVGGlyphRefElement(child)->hasValidGlyphElement(referredGlyphName)) glyphNames.append(referredGlyphName); else { glyphNames.clear(); return false; } } } return !glyphNames.isEmpty(); }
String HTMLMediaElement::pickMedia() { // 3.14.9.2. Location of the media resource String mediaSrc = getAttribute(srcAttr); if (mediaSrc.isEmpty()) { for (Node* n = firstChild(); n; n = n->nextSibling()) { if (n->hasTagName(sourceTag)) { HTMLSourceElement* source = static_cast<HTMLSourceElement*>(n); if (!source->hasAttribute(srcAttr)) continue; if (source->hasAttribute(mediaAttr)) { MediaQueryEvaluator screenEval("screen", document()->frame(), renderer() ? renderer()->style() : 0); RefPtr<MediaList> media = MediaList::createAllowingDescriptionSyntax(source->media()); if (!screenEval.eval(media.get())) continue; } if (source->hasAttribute(typeAttr)) { String type = source->type().stripWhiteSpace(); // "type" can have parameters after a semi-colon, strip them before checking with the type registry int semi = type.find(';'); if (semi != -1) type = type.left(semi).stripWhiteSpace(); if (!MIMETypeRegistry::isSupportedMediaMIMEType(type)) continue; } mediaSrc = source->src().string(); break; } } } if (!mediaSrc.isEmpty()) mediaSrc = document()->completeURL(mediaSrc).string(); return mediaSrc; }
JSValue JSHTMLDocument::nameGetter(ExecState* exec, JSValue slotBase, const Identifier& propertyName) { JSHTMLDocument* thisObj = static_cast<JSHTMLDocument*>(asObject(slotBase)); HTMLDocument* document = static_cast<HTMLDocument*>(thisObj->impl()); String name = identifierToString(propertyName); RefPtr<HTMLCollection> collection = document->documentNamedItems(name); unsigned length = collection->length(); if (!length) return jsUndefined(); if (length == 1) { Node* node = collection->firstItem(); Frame* frame; if (node->hasTagName(iframeTag) && (frame = static_cast<HTMLIFrameElement*>(node)->contentFrame())) return toJS(exec, frame); return toJS(exec, node); } return toJS(exec, collection.get()); }
JSValue* JSHTMLDocument::nameGetter(ExecState* exec, JSObject* originalObject, const Identifier& propertyName, const PropertySlot& slot) { JSHTMLDocument* thisObj = static_cast<JSHTMLDocument*>(slot.slotBase()); HTMLDocument* doc = static_cast<HTMLDocument*>(thisObj->impl()); String name = propertyName; RefPtr<HTMLCollection> collection = doc->documentNamedItems(name); unsigned length = collection->length(); if (!length) return jsUndefined(); if (length == 1) { Node* node = collection->firstItem(); Frame* frame; if (node->hasTagName(iframeTag) && (frame = static_cast<HTMLIFrameElement*>(node)->contentFrame())) return Window::retrieve(frame); return toJS(exec, node); } return toJS(exec, collection.get()); }
bool FocusController::advanceFocusDirectionally(FocusDirection direction, KeyboardEvent* event) { Frame* curFrame = focusedOrMainFrame(); ASSERT(curFrame); Document* focusedDocument = curFrame->document(); if (!focusedDocument) return false; Node* focusedNode = focusedDocument->focusedNode(); Node* container = focusedDocument; // Figure out the starting rect. IntRect startingRect; if (focusedNode) { if (!hasOffscreenRect(focusedNode)) { container = scrollableEnclosingBoxOrParentFrameForNodeInDirection(direction, focusedNode); startingRect = nodeRectInAbsoluteCoordinates(focusedNode, true /* ignore border */); } else if (focusedNode->hasTagName(areaTag)) { HTMLAreaElement* area = static_cast<HTMLAreaElement*>(focusedNode); container = scrollableEnclosingBoxOrParentFrameForNodeInDirection(direction, area->imageElement()); startingRect = virtualRectForAreaElementAndDirection(area, direction); } } bool consumed = false; do { if (container->isDocumentNode()) static_cast<Document*>(container)->updateLayoutIgnorePendingStylesheets(); consumed = advanceFocusDirectionallyInContainer(container, startingRect, direction, event); startingRect = nodeRectInAbsoluteCoordinates(container, true /* ignore border */); container = scrollableEnclosingBoxOrParentFrameForNodeInDirection(direction, container); } while (!consumed && container); return consumed; }
void FormatBlockCommand::formatRange(const Position&, const Position& end, RefPtr<Element>&) { setEndingSelection(VisiblePosition(end)); Node* refNode = enclosingBlockFlowElement(endingSelection().visibleStart()); if (refNode->hasTagName(tagName())) // We're already in a block with the format we want, so we don't have to do anything return; VisiblePosition paragraphStart = startOfParagraph(end); VisiblePosition paragraphEnd = endOfParagraph(end); VisiblePosition blockStart = startOfBlock(endingSelection().visibleStart()); VisiblePosition blockEnd = endOfBlock(endingSelection().visibleStart()); RefPtr<Element> blockNode = createBlockElement(); RefPtr<Element> placeholder = createBreakElement(document()); Node* root = endingSelection().start().node()->rootEditableElement(); if (validBlockTag(refNode->nodeName().lower()) && paragraphStart == blockStart && paragraphEnd == blockEnd && refNode != root && !root->isDescendantOf(refNode)) // Already in a valid block tag that only contains the current paragraph, so we can swap with the new tag insertNodeBefore(blockNode, refNode); else { // Avoid inserting inside inline elements that surround paragraphStart with upstream(). // This is only to avoid creating bloated markup. insertNodeAt(blockNode, paragraphStart.deepEquivalent().upstream()); } appendNode(placeholder, blockNode); VisiblePosition destination(Position(placeholder.get(), 0)); if (paragraphStart == paragraphEnd && !lineBreakExistsAtVisiblePosition(paragraphStart)) { setEndingSelection(destination); return; } moveParagraph(paragraphStart, paragraphEnd, destination, true, false); }
// This function chooses the focused element when showModal() is invoked, as described in the spec for showModal(). static void setFocusForModalDialog(HTMLDialogElement* dialog) { Element* focusableDescendant = 0; Node* next = 0; for (Node* node = dialog->firstChild(); node; node = next) { if (node->hasTagName(dialogTag)) next = NodeTraversal::nextSkippingChildren(*node, dialog); else next = NodeTraversal::next(*node, dialog); if (!node->isElementNode()) continue; Element* element = toElement(node); if (element->isFormControlElement()) { HTMLFormControlElement* control = toHTMLFormControlElement(node); if (control->isAutofocusable()) { control->focus(); return; } } if (!focusableDescendant && element->isFocusable()) focusableDescendant = element; } if (focusableDescendant) { focusableDescendant->focus(); return; } if (dialog->isFocusable()) { dialog->focus(); return; } dialog->document().setFocusedElement(0); }
AXObject* AXTableRow::headerObject() { if (!m_renderer || !m_renderer->isTableRow()) return 0; AccessibilityChildrenVector rowChildren = children(); if (!rowChildren.size()) return 0; // check the first element in the row to see if it is a TH element AXObject* cell = rowChildren[0].get(); if (!cell->isTableCell()) return 0; RenderObject* cellRenderer = toAXTableCell(cell)->renderer(); if (!cellRenderer) return 0; Node* cellNode = cellRenderer->node(); if (!cellNode || !cellNode->hasTagName(thTag)) return 0; return cell; }
void RenderImage::paintAreaElementFocusRing(PaintInfo& paintInfo) { Document* document = this->document(); if (document->printing() || !document->frame()->selection()->isFocusedAndActive()) return; if (paintInfo.context->paintingDisabled() && !paintInfo.context->updatingControlTints()) return; Node* focusedNode = document->focusedNode(); if (!focusedNode || !focusedNode->hasTagName(areaTag)) return; HTMLAreaElement* areaElement = static_cast<HTMLAreaElement*>(focusedNode); if (areaElement->imageElement() != node()) return; // Even if the theme handles focus ring drawing for entire elements, it won't do it for // an area within an image, so we don't call RenderTheme::supportsFocusRing here. Path path = areaElement->computePath(this); if (path.isEmpty()) return; // FIXME: Do we need additional code to clip the path to the image's bounding box? RenderStyle* areaElementStyle = areaElement->computedStyle(); unsigned short outlineWidth = areaElementStyle->outlineWidth(); if (!outlineWidth) return; paintInfo.context->drawFocusRing(path, outlineWidth, areaElementStyle->outlineOffset(), areaElementStyle->visitedDependentColor(CSSPropertyOutlineColor)); }
AccessibilityObject* AccessibilityTableRow::headerObject() { if (!m_renderer || !m_renderer->isTableRow()) return nullptr; const auto& rowChildren = children(); if (!rowChildren.size()) return nullptr; // check the first element in the row to see if it is a TH element AccessibilityObject* cell = rowChildren[0].get(); if (!is<AccessibilityTableCell>(*cell)) return nullptr; RenderObject* cellRenderer = downcast<AccessibilityTableCell>(*cell).renderer(); if (!cellRenderer) return nullptr; Node* cellNode = cellRenderer->node(); if (!cellNode || !cellNode->hasTagName(thTag)) return nullptr; return cell; }
void SVGUseElement::updateContainerOffsets() { if (!m_targetElementInstance) return; // Update root container offset (not reachable through instance tree) SVGElement* shadowRoot = m_targetElementInstance->shadowTreeElement(); ASSERT(shadowRoot); Node* parentNode = shadowRoot->parentNode(); ASSERT(parentNode); ASSERT(parentNode->isSVGElement()); ASSERT(parentNode->hasTagName(SVGNames::gTag)); ASSERT(static_cast<SVGGElement*>(parentNode)->isShadowTreeContainerElement()); SVGShadowTreeContainerElement* containerElement = static_cast<SVGShadowTreeContainerElement*>(parentNode); containerElement->setContainerOffset(x(), y()); // Update whole subtree, scanning for shadow container elements, marking a cloned use subtree updateContainerOffset(m_targetElementInstance.get()); if (renderer()) renderer()->setNeedsLayout(true); }
AccessibilityObject* AccessibilityTableCell::titleUIElement() const { // Try to find if the first cell in this row is a <th>. If it is, // then it can act as the title ui element. (This is only in the // case when the table is not appearing as an AXTable.) if (isTableCell() || !m_renderer || !m_renderer->isTableCell()) return 0; // Table cells that are th cannot have title ui elements, since by definition // they are title ui elements Node* node = m_renderer->node(); if (node && node->hasTagName(thTag)) return 0; RenderTableCell* renderCell = toRenderTableCell(m_renderer); // If this cell is in the first column, there is no need to continue. int col = renderCell->col(); if (!col) return 0; int row = renderCell->rowIndex(); RenderTableSection* section = renderCell->section(); if (!section) return 0; RenderTableCell* headerCell = section->primaryCellAt(row, 0); if (!headerCell || headerCell == renderCell) return 0; if (!headerCell->element() || !headerCell->element()->hasTagName(thTag)) return 0; return axObjectCache()->getOrCreate(headerCell); }
HTMLElement* HTMLTextAreaElement::innerTextElement() const { Node* node = shadow()->oldestShadowRoot()->firstChild(); ASSERT(!node || node->hasTagName(divTag)); return toHTMLElement(node); }
SimpleFontData* CSSFontFaceSource::getFontData(const FontDescription& fontDescription, bool syntheticBold, bool syntheticItalic, CSSFontSelector* fontSelector) { // If the font hasn't loaded or an error occurred, then we've got nothing. if (!isValid()) return 0; #if ENABLE(SVG_FONTS) if (!m_font && !m_svgFontFaceElement) { #else if (!m_font) { #endif SimpleFontData* fontData = fontCache()->getCachedFontData(fontDescription, m_string); // We're local. Just return a SimpleFontData from the normal cache. return fontData; } // See if we have a mapping in our FontData cache. unsigned hashKey = (fontDescription.computedPixelSize() + 1) << 6 | fontDescription.widthVariant() << 4 | (fontDescription.textOrientation() == TextOrientationUpright ? 8 : 0) | (fontDescription.orientation() == Vertical ? 4 : 0) | (syntheticBold ? 2 : 0) | (syntheticItalic ? 1 : 0); if (SimpleFontData* cachedData = m_fontDataTable.get(hashKey)) return cachedData; OwnPtr<SimpleFontData> fontData; // If we are still loading, then we let the system pick a font. if (isLoaded()) { if (m_font) { #if ENABLE(SVG_FONTS) if (m_hasExternalSVGFont) { // For SVG fonts parse the external SVG document, and extract the <font> element. if (!m_font->ensureSVGFontData()) return 0; if (!m_externalSVGFontElement) m_externalSVGFontElement = m_font->getSVGFontById(SVGURIReference::getTarget(m_string)); if (!m_externalSVGFontElement) return 0; SVGFontFaceElement* fontFaceElement = 0; // Select first <font-face> child for (Node* fontChild = m_externalSVGFontElement->firstChild(); fontChild; fontChild = fontChild->nextSibling()) { if (fontChild->hasTagName(SVGNames::font_faceTag)) { fontFaceElement = static_cast<SVGFontFaceElement*>(fontChild); break; } } if (fontFaceElement) { if (!m_svgFontFaceElement) { // We're created using a CSS @font-face rule, that means we're not associated with a SVGFontFaceElement. // Use the imported <font-face> tag as referencing font-face element for these cases. m_svgFontFaceElement = fontFaceElement; } fontData.set(new SimpleFontData(adoptPtr(new SVGFontData(fontFaceElement)), fontDescription.computedPixelSize(), syntheticBold, syntheticItalic)); } } else #endif { // Create new FontPlatformData from our CGFontRef, point size and ATSFontRef. if (!m_font->ensureCustomFontData()) return 0; fontData.set(new SimpleFontData(m_font->platformDataFromCustomData(fontDescription.computedPixelSize(), syntheticBold, syntheticItalic, fontDescription.orientation(), fontDescription.textOrientation(), fontDescription.widthVariant(), fontDescription.renderingMode()), true, false)); } } else { #if ENABLE(SVG_FONTS) // In-Document SVG Fonts if (m_svgFontFaceElement) fontData.set(new SimpleFontData(adoptPtr(new SVGFontData(m_svgFontFaceElement.get())), fontDescription.computedPixelSize(), syntheticBold, syntheticItalic)); #endif } } else { // Kick off the load now. if (CachedResourceLoader* cachedResourceLoader = fontSelector->cachedResourceLoader()) m_font->beginLoadIfNeeded(cachedResourceLoader); // FIXME: m_string is a URL so it makes no sense to pass it as a family name. SimpleFontData* tempData = fontCache()->getCachedFontData(fontDescription, m_string); if (!tempData) tempData = fontCache()->getLastResortFallbackFont(fontDescription); fontData.set(new SimpleFontData(tempData->platformData(), true, true)); } SimpleFontData* fontDataRawPtr = fontData.leakPtr(); m_fontDataTable.set(hashKey, fontDataRawPtr); return fontDataRawPtr; } #if ENABLE(SVG_FONTS) SVGFontFaceElement* CSSFontFaceSource::svgFontFaceElement() const { return m_svgFontFaceElement.get(); } void CSSFontFaceSource::setSVGFontFaceElement(PassRefPtr<SVGFontFaceElement> element) { m_svgFontFaceElement = element; } bool CSSFontFaceSource::isSVGFontFaceSource() const { return m_svgFontFaceElement || m_hasExternalSVGFont; } #endif }
void WMLCardElement::handleIntrinsicEventIfNeeded() { WMLPageState* pageState = wmlPageStateForDocument(document()); if (!pageState) return; Frame* frame = document()->frame(); if (!frame) return; FrameLoader* loader = frame->loader(); if (!loader) return; // Calculate the entry method of current card WMLIntrinsicEventType eventType = WMLIntrinsicEventUnknown; switch (loader->policyChecker()->loadType()) { case FrameLoadTypeReload: break; case FrameLoadTypeBack: eventType = WMLIntrinsicEventOnEnterBackward; break; case FrameLoadTypeBackWMLDeckNotAccessible: reportWMLError(document(), WMLErrorDeckNotAccessible); return; default: eventType = WMLIntrinsicEventOnEnterForward; break; } // Figure out target event handler WMLIntrinsicEventHandler* eventHandler = this->eventHandler(); bool hasIntrinsicEvent = false; if (eventType != WMLIntrinsicEventUnknown) { if (eventHandler && eventHandler->hasIntrinsicEvent(eventType)) hasIntrinsicEvent = true; else if (m_template) { eventHandler = m_template->eventHandler(); if (eventHandler && eventHandler->hasIntrinsicEvent(eventType)) hasIntrinsicEvent = true; } } if (hasIntrinsicEvent) eventHandler->triggerIntrinsicEvent(eventType); // Start the timer if it exists in current card if (m_eventTimer && eventType != WMLIntrinsicEventOnEnterBackward) m_eventTimer->start(); /*guoxiaolei 20120827 end>*/ for (Node* node = traverseNextNode(); node != 0; node = node->traverseNextNode()) { if (!node->isElementNode()) continue; if (node->hasTagName(inputTag)) static_cast<WMLInputElement*>(node)->initialize(); else if (node->hasTagName(selectTag)) static_cast<WMLSelectElement*>(node)->selectInitialOptions(); } }
// FIXME: This function should not deal with url or serviceType! void HTMLObjectElement::parametersForPlugin(Vector<String>& paramNames, Vector<String>& paramValues, String& url, String& serviceType) { HashSet<StringImpl*, CaseFoldingHash> uniqueParamNames; String urlParameter; // Scan the PARAM children and store their name/value pairs. // Get the URL and type from the params if we don't already have them. for (Node* child = firstChild(); child; child = child->nextSibling()) { if (!child->hasTagName(paramTag)) continue; HTMLParamElement* p = static_cast<HTMLParamElement*>(child); String name = p->name(); if (name.isEmpty()) continue; uniqueParamNames.add(name.impl()); paramNames.append(p->name()); paramValues.append(p->value()); // FIXME: url adjustment does not belong in this function. if (url.isEmpty() && urlParameter.isEmpty() && (equalIgnoringCase(name, "src") || equalIgnoringCase(name, "movie") || equalIgnoringCase(name, "code") || equalIgnoringCase(name, "url"))) urlParameter = stripLeadingAndTrailingHTMLSpaces(p->value()); // FIXME: serviceType calculation does not belong in this function. if (serviceType.isEmpty() && equalIgnoringCase(name, "type")) { serviceType = p->value(); size_t pos = serviceType.find(";"); if (pos != notFound) serviceType = serviceType.left(pos); } } // When OBJECT is used for an applet via Sun's Java plugin, the CODEBASE attribute in the tag // points to the Java plugin itself (an ActiveX component) while the actual applet CODEBASE is // in a PARAM tag. See <http://java.sun.com/products/plugin/1.2/docs/tags.html>. This means // we have to explicitly suppress the tag's CODEBASE attribute if there is none in a PARAM, // else our Java plugin will misinterpret it. [4004531] String codebase; if (MIMETypeRegistry::isJavaAppletMIMEType(serviceType)) { codebase = "codebase"; uniqueParamNames.add(codebase.impl()); // pretend we found it in a PARAM already } // Turn the attributes of the <object> element into arrays, but don't override <param> values. if (hasAttributes()) { for (unsigned i = 0; i < attributeCount(); ++i) { Attribute* it = attributeItem(i); const AtomicString& name = it->name().localName(); if (!uniqueParamNames.contains(name.impl())) { paramNames.append(name.string()); paramValues.append(it->value().string()); } } } mapDataParamToSrc(¶mNames, ¶mValues); // HTML5 says that an object resource's URL is specified by the object's data // attribute, not by a param element. However, for compatibility, allow the // resource's URL to be given by a param named "src", "movie", "code" or "url" // if we know that resource points to a plug-in. if (url.isEmpty() && !urlParameter.isEmpty()) { SubframeLoader* loader = document()->frame()->loader()->subframeLoader(); if (loader->resourceWillUsePlugin(urlParameter, serviceType, shouldPreferPlugInsForImages())) url = urlParameter; } }
void RenderTheme::paintSliderTicks(RenderObject* o, const PaintInfo& paintInfo, const IntRect& rect) { Node* node = o->node(); if (!node) return; HTMLInputElement* input = node->toInputElement(); if (!input) return; HTMLDataListElement* dataList = static_cast<HTMLDataListElement*>(input->list()); if (!dataList) return; double min = input->minimum(); double max = input->maximum(); ControlPart part = o->style()->appearance(); // We don't support ticks on alternate sliders like MediaVolumeSliders. if (part != SliderHorizontalPart && part != SliderVerticalPart) return; bool isHorizontal = part == SliderHorizontalPart; IntSize thumbSize; RenderObject* thumbRenderer = input->sliderThumbElement()->renderer(); if (thumbRenderer) { RenderStyle* thumbStyle = thumbRenderer->style(); int thumbWidth = thumbStyle->width().intValue(); int thumbHeight = thumbStyle->height().intValue(); thumbSize.setWidth(isHorizontal ? thumbWidth : thumbHeight); thumbSize.setHeight(isHorizontal ? thumbHeight : thumbWidth); } IntSize tickSize = sliderTickSize(); float zoomFactor = o->style()->effectiveZoom(); FloatRect tickRect; int tickRegionSideMargin = 0; int tickRegionWidth = 0; IntRect trackBounds; RenderObject* trackRenderer = input->sliderTrackElement()->renderer(); // We can ignoring transforms because transform is handled by the graphics context. if (trackRenderer) trackBounds = trackRenderer->absoluteBoundingBoxRectIgnoringTransforms(); IntRect sliderBounds = o->absoluteBoundingBoxRectIgnoringTransforms(); // Make position relative to the transformed ancestor element. trackBounds.setX(trackBounds.x() - sliderBounds.x() + rect.x()); trackBounds.setY(trackBounds.y() - sliderBounds.y() + rect.y()); if (isHorizontal) { tickRect.setWidth(floor(tickSize.width() * zoomFactor)); tickRect.setHeight(floor(tickSize.height() * zoomFactor)); tickRect.setY(floor(rect.y() + rect.height() / 2.0 + sliderTickOffsetFromTrackCenter() * zoomFactor)); tickRegionSideMargin = trackBounds.x() + (thumbSize.width() - tickSize.width() * zoomFactor) / 2.0; tickRegionWidth = trackBounds.width() - thumbSize.width(); } else { tickRect.setWidth(floor(tickSize.height() * zoomFactor)); tickRect.setHeight(floor(tickSize.width() * zoomFactor)); tickRect.setX(floor(rect.x() + rect.width() / 2.0 + sliderTickOffsetFromTrackCenter() * zoomFactor)); tickRegionSideMargin = trackBounds.y() + (thumbSize.width() - tickSize.width() * zoomFactor) / 2.0; tickRegionWidth = trackBounds.height() - thumbSize.width(); } RefPtr<HTMLCollection> options = dataList->options(); GraphicsContextStateSaver stateSaver(*paintInfo.context); paintInfo.context->setFillColor(o->style()->visitedDependentColor(CSSPropertyColor), ColorSpaceDeviceRGB); for (unsigned i = 0; Node* node = options->item(i); i++) { ASSERT(node->hasTagName(optionTag)); HTMLOptionElement* optionElement = toHTMLOptionElement(node); String value = optionElement->value(); if (!input->isValidValue(value)) continue; double parsedValue = parseToDoubleForNumberType(input->sanitizeValue(value)); double tickFraction = (parsedValue - min) / (max - min); double tickRatio = isHorizontal && o->style()->isLeftToRightDirection() ? tickFraction : 1.0 - tickFraction; double tickPosition = round(tickRegionSideMargin + tickRegionWidth * tickRatio); if (isHorizontal) tickRect.setX(tickPosition); else tickRect.setY(tickPosition); paintInfo.context->fillRect(tickRect); } }
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 = toElement(n); AtomicString title = e->getAttribute(titleAttr); bool enabledViaScript = false; if (e->hasTagName(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 (e->hasTagName(SVGNames::styleTag)) sheet = static_cast<SVGStyleElement*>(n)->sheet(); else #endif { if (e->hasTagName(linkTag)) sheet = static_cast<HTMLLinkElement*>(n)->sheet(); else // <STYLE> element sheet = toHTMLStyleElement(e)->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->hasTagName(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); } }
Position VisiblePosition::canonicalPosition(const Position& passedPosition) { // The updateLayout call below can do so much that even the position passed // in to us might get changed as a side effect. Specifically, there are code // paths that pass selection endpoints, and updateLayout can change the selection. Position position = passedPosition; // FIXME (9535): Canonicalizing to the leftmost candidate means that if we're at a line wrap, we will // ask renderers to paint downstream carets for other renderers. // To fix this, we need to either a) add code to all paintCarets to pass the responsibility off to // the appropriate renderer for VisiblePosition's like these, or b) canonicalize to the rightmost candidate // unless the affinity is upstream. if (position.isNull()) return Position(); ASSERT(position.document()); position.document()->updateLayoutIgnorePendingStylesheets(); Node* node = position.containerNode(); Position candidate = position.upstream(); if (candidate.isCandidate()) return candidate; candidate = position.downstream(); if (candidate.isCandidate()) return candidate; // When neither upstream or downstream gets us to a candidate (upstream/downstream won't leave // blocks or enter new ones), we search forward and backward until we find one. Position next = canonicalizeCandidate(nextCandidate(position)); Position prev = canonicalizeCandidate(previousCandidate(position)); Node* nextNode = next.deprecatedNode(); Node* prevNode = prev.deprecatedNode(); // The new position must be in the same editable element. Enforce that first. // Unless the descent is from a non-editable html element to an editable body. if (node && node->hasTagName(htmlTag) && !node->rendererIsEditable() && node->document()->body() && node->document()->body()->rendererIsEditable()) return next.isNotNull() ? next : prev; Node* editingRoot = editableRootForPosition(position); // If the html element is editable, descending into its body will look like a descent // from non-editable to editable content since rootEditableElement() always stops at the body. if ((editingRoot && editingRoot->hasTagName(htmlTag)) || position.deprecatedNode()->isDocumentNode()) return next.isNotNull() ? next : prev; bool prevIsInSameEditableElement = prevNode && editableRootForPosition(prev) == editingRoot; bool nextIsInSameEditableElement = nextNode && editableRootForPosition(next) == editingRoot; if (prevIsInSameEditableElement && !nextIsInSameEditableElement) return prev; if (nextIsInSameEditableElement && !prevIsInSameEditableElement) return next; if (!nextIsInSameEditableElement && !prevIsInSameEditableElement) return Position(); // The new position should be in the same block flow element. Favor that. Node* originalBlock = node ? node->enclosingBlockFlowElement() : 0; bool nextIsOutsideOriginalBlock = !nextNode->isDescendantOf(originalBlock) && nextNode != originalBlock; bool prevIsOutsideOriginalBlock = !prevNode->isDescendantOf(originalBlock) && prevNode != originalBlock; if (nextIsOutsideOriginalBlock && !prevIsOutsideOriginalBlock) return prev; return next; }
void BreakBlockquoteCommand::doApply() { if (endingSelection().isNone()) return; // Delete the current selection. if (endingSelection().isRange()) deleteSelection(false, false); // This is a scenario that should never happen, but we want to // make sure we don't dereference a null pointer below. ASSERT(!endingSelection().isNone()); if (endingSelection().isNone()) return; VisiblePosition visiblePos = endingSelection().visibleStart(); // pos is a position equivalent to the caret. We use downstream() so that pos will // be in the first node that we need to move (there are a few exceptions to this, see below). Position pos = endingSelection().start().downstream(); // Find the top-most blockquote from the start. Node* topBlockquote = highestEnclosingNodeOfType(pos, isMailBlockquote); if (!topBlockquote || !topBlockquote->parentNode() || !topBlockquote->isElementNode()) return; RefPtr<Element> breakNode = createBreakElement(document()); bool isLastVisPosInNode = isLastVisiblePositionInNode(visiblePos, topBlockquote); // If the position is at the beginning of the top quoted content, we don't need to break the quote. // Instead, insert the break before the blockquote, unless the position is as the end of the the quoted content. if (isFirstVisiblePositionInNode(visiblePos, topBlockquote) && !isLastVisPosInNode) { insertNodeBefore(breakNode.get(), topBlockquote); setEndingSelection(VisibleSelection(positionBeforeNode(breakNode.get()), DOWNSTREAM, endingSelection().isDirectional())); rebalanceWhitespace(); return; } // Insert a break after the top blockquote. insertNodeAfter(breakNode.get(), topBlockquote); // If we're inserting the break at the end of the quoted content, we don't need to break the quote. if (isLastVisPosInNode) { setEndingSelection(VisibleSelection(positionBeforeNode(breakNode.get()), DOWNSTREAM, endingSelection().isDirectional())); rebalanceWhitespace(); return; } // Don't move a line break just after the caret. Doing so would create an extra, empty paragraph // in the new blockquote. if (lineBreakExistsAtVisiblePosition(visiblePos)) pos = pos.next(); // Adjust the position so we don't split at the beginning of a quote. while (isFirstVisiblePositionInNode(VisiblePosition(pos), enclosingNodeOfType(pos, isMailBlockquote))) pos = pos.previous(); // startNode is the first node that we need to move to the new blockquote. Node* startNode = pos.deprecatedNode(); // Split at pos if in the middle of a text node. if (startNode->isTextNode()) { Text* textNode = toText(startNode); if ((unsigned)pos.deprecatedEditingOffset() >= textNode->length()) { startNode = NodeTraversal::next(startNode); ASSERT(startNode); } else if (pos.deprecatedEditingOffset() > 0) splitTextNode(textNode, pos.deprecatedEditingOffset()); } else if (pos.deprecatedEditingOffset() > 0) { Node* childAtOffset = startNode->childNode(pos.deprecatedEditingOffset()); startNode = childAtOffset ? childAtOffset : NodeTraversal::next(startNode); ASSERT(startNode); } // If there's nothing inside topBlockquote to move, we're finished. if (!startNode->isDescendantOf(topBlockquote)) { setEndingSelection(VisibleSelection(VisiblePosition(firstPositionInOrBeforeNode(startNode)), endingSelection().isDirectional())); return; } // Build up list of ancestors in between the start node and the top blockquote. Vector<RefPtr<Element> > ancestors; for (Element* node = startNode->parentElement(); node && node != topBlockquote; node = node->parentElement()) ancestors.append(node); // Insert a clone of the top blockquote after the break. RefPtr<Element> clonedBlockquote = toElement(topBlockquote)->cloneElementWithoutChildren(); insertNodeAfter(clonedBlockquote.get(), breakNode.get()); // Clone startNode's ancestors into the cloned blockquote. // On exiting this loop, clonedAncestor is the lowest ancestor // that was cloned (i.e. the clone of either ancestors.last() // or clonedBlockquote if ancestors is empty). RefPtr<Element> clonedAncestor = clonedBlockquote; for (size_t i = ancestors.size(); i != 0; --i) { RefPtr<Element> clonedChild = ancestors[i - 1]->cloneElementWithoutChildren(); // Preserve list item numbering in cloned lists. if (clonedChild->isElementNode() && clonedChild->hasTagName(olTag)) { Node* listChildNode = i > 1 ? ancestors[i - 2].get() : startNode; // The first child of the cloned list might not be a list item element, // find the first one so that we know where to start numbering. while (listChildNode && !listChildNode->hasTagName(liTag)) listChildNode = listChildNode->nextSibling(); if (listChildNode && listChildNode->renderer() && listChildNode->renderer()->isListItem()) setNodeAttribute(clonedChild, startAttr, String::number(toRenderListItem(listChildNode->renderer())->value())); } appendNode(clonedChild.get(), clonedAncestor.get()); clonedAncestor = clonedChild; } moveRemainingSiblingsToNewParent(startNode, 0, clonedAncestor); if (!ancestors.isEmpty()) { // Split the tree up the ancestor chain until the topBlockquote // Throughout this loop, clonedParent is the clone of ancestor's parent. // This is so we can clone ancestor's siblings and place the clones // into the clone corresponding to the ancestor's parent. RefPtr<Element> ancestor; RefPtr<Element> clonedParent; for (ancestor = ancestors.first(), clonedParent = clonedAncestor->parentElement(); ancestor && ancestor != topBlockquote; ancestor = ancestor->parentElement(), clonedParent = clonedParent->parentElement()) moveRemainingSiblingsToNewParent(ancestor->nextSibling(), 0, clonedParent); // If the startNode's original parent is now empty, remove it Node* originalParent = ancestors.first().get(); if (!originalParent->hasChildNodes()) removeNode(originalParent); } // Make sure the cloned block quote renders. addBlockPlaceholderIfNeeded(clonedBlockquote.get()); // Put the selection right before the break. setEndingSelection(VisibleSelection(positionBeforeNode(breakNode.get()), DOWNSTREAM, endingSelection().isDirectional())); rebalanceWhitespace(); }
String Frame::searchForLabelsBeforeElement(const Vector<String>& labels, Element* element, size_t* resultDistance, bool* resultIsInCellAbove) { OwnPtr<RegularExpression> regExp(createRegExpForLabels(labels)); // We stop searching after we've seen this many chars const unsigned int charsSearchedThreshold = 500; // This is the absolute max we search. We allow a little more slop than // charsSearchedThreshold, to make it more likely that we'll search whole nodes. const unsigned int maxCharsSearched = 600; // If the starting element is within a table, the cell that contains it HTMLTableCellElement* startingTableCell = 0; bool searchedCellAbove = false; if (resultDistance) *resultDistance = notFound; if (resultIsInCellAbove) *resultIsInCellAbove = false; // walk backwards in the node tree, until another element, or form, or end of tree int unsigned lengthSearched = 0; Node* n; for (n = element->traversePreviousNode(); n && lengthSearched < charsSearchedThreshold; n = n->traversePreviousNode()) { if (n->hasTagName(formTag) || (n->isHTMLElement() && static_cast<Element*>(n)->isFormControlElement())) { // We hit another form element or the start of the form - bail out break; } else if (n->hasTagName(tdTag) && !startingTableCell) { startingTableCell = static_cast<HTMLTableCellElement*>(n); } else if (n->hasTagName(trTag) && startingTableCell) { String result = searchForLabelsAboveCell(regExp.get(), startingTableCell, resultDistance); if (!result.isEmpty()) { if (resultIsInCellAbove) *resultIsInCellAbove = true; return result; } searchedCellAbove = true; } else if (n->isTextNode() && n->renderer() && n->renderer()->style()->visibility() == VISIBLE) { // For each text chunk, run the regexp String nodeString = n->nodeValue(); // add 100 for slop, to make it more likely that we'll search whole nodes if (lengthSearched + nodeString.length() > maxCharsSearched) nodeString = nodeString.right(charsSearchedThreshold - lengthSearched); int pos = regExp->searchRev(nodeString); if (pos >= 0) { if (resultDistance) *resultDistance = lengthSearched; return nodeString.substring(pos, regExp->matchedLength()); } lengthSearched += nodeString.length(); } } // If we started in a cell, but bailed because we found the start of the form or the // previous element, we still might need to search the row above us for a label. if (startingTableCell && !searchedCellAbove) { String result = searchForLabelsAboveCell(regExp.get(), startingTableCell, resultDistance); if (!result.isEmpty()) { if (resultIsInCellAbove) *resultIsInCellAbove = true; return result; } } return String(); }