void HTMLFormElement::getNamedElements(const AtomicString& name, WillBeHeapVector<RefPtrWillBeMember<Element>>& namedItems) { // http://www.whatwg.org/specs/web-apps/current-work/multipage/forms.html#dom-form-nameditem elements()->namedItems(name, namedItems); Element* elementFromPast = elementFromPastNamesMap(name); if (namedItems.size() && namedItems.first() != elementFromPast) { addToPastNamesMap(namedItems.first().get(), name); } else if (elementFromPast && namedItems.isEmpty()) { namedItems.append(elementFromPast); UseCounter::count(document(), UseCounter::FormNameAccessForPastNamesMap); } }
Element* HTMLCollection::namedItem(const AtomicString& name) const { // http://msdn.microsoft.com/workshop/author/dhtml/reference/methods/nameditem.asp // This method first searches for an object with a matching id // attribute. If a match is not found, the method then searches for an // object with a matching name attribute, but only on those elements // that are allowed a name attribute. updateIdNameCache(); const NamedItemCache& cache = namedItemCache(); WillBeHeapVector<RawPtrWillBeMember<Element>>* idResults = cache.getElementsById(name); if (idResults && !idResults->isEmpty()) return idResults->first(); WillBeHeapVector<RawPtrWillBeMember<Element>>* nameResults = cache.getElementsByName(name); if (nameResults && !nameResults->isEmpty()) return nameResults->first(); return nullptr; }
void HTMLFormElement::anonymousNamedGetter(const AtomicString& name, RadioNodeListOrElement& returnValue) { // Call getNamedElements twice, first time check if it has a value // and let HTMLFormElement update its cache. // See issue: 867404 { WillBeHeapVector<RefPtrWillBeMember<Element>> elements; getNamedElements(name, elements); if (elements.isEmpty()) return; } // Second call may return different results from the first call, // but if the first the size cannot be zero. WillBeHeapVector<RefPtrWillBeMember<Element>> elements; getNamedElements(name, elements); ASSERT(!elements.isEmpty()); bool onlyMatchImg = !elements.isEmpty() && isHTMLImageElement(*elements.first()); if (onlyMatchImg) { UseCounter::count(document(), UseCounter::FormNameAccessForImageElement); // The following code has performance impact, but it should be small // because <img> access via <form> name getter is rarely used. for (auto& element : elements) { if (isHTMLImageElement(*element) && !element->isDescendantOf(this)) { UseCounter::count(document(), UseCounter::FormNameAccessForNonDescendantImageElement); break; } } } if (elements.size() == 1) { returnValue.setElement(elements.at(0)); return; } returnValue.setRadioNodeList(radioNodeList(name, onlyMatchImg)); }
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 = mostForwardCaretPosition(endingSelection().start()); // Find the top-most blockquote from the start. HTMLQuoteElement* topBlockquote = toHTMLQuoteElement(highestEnclosingNodeOfType(pos, isMailHTMLBlockquoteElement)); if (!topBlockquote || !topBlockquote->parentNode()) return; RefPtrWillBeRawPtr<HTMLBRElement> breakElement = 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(breakElement.get(), topBlockquote); setEndingSelection(VisibleSelection(positionBeforeNode(breakElement.get()), TextAffinity::Downstream, endingSelection().isDirectional())); rebalanceWhitespace(); return; } // Insert a break after the top blockquote. insertNodeAfter(breakElement.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(breakElement.get()), TextAffinity::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)) { // TODO(yosin) We should use |PositionMoveType::Character| for // |nextPositionOf()| to avoid editing middle of character. pos = nextPositionOf(pos, PositionMoveType::CodePoint); } // Adjust the position so we don't split at the beginning of a quote. while (isFirstVisiblePositionInNode(createVisiblePosition(pos), toHTMLQuoteElement(enclosingNodeOfType(pos, isMailHTMLBlockquoteElement)))) { // TODO(yosin) We should use |PositionMoveType::Character| for // |previousPositionOf()| to avoid editing middle character. pos = previousPositionOf(pos, PositionMoveType::CodePoint); } // startNode is the first node that we need to move to the new blockquote. Node* startNode = pos.anchorNode(); ASSERT(startNode); // Split at pos if in the middle of a text node. if (startNode->isTextNode()) { Text* textNode = toText(startNode); int textOffset = pos.computeOffsetInContainerNode(); if ((unsigned)textOffset >= textNode->length()) { startNode = NodeTraversal::next(*startNode); ASSERT(startNode); } else if (textOffset > 0) { splitTextNode(textNode, textOffset); } } else if (pos.computeEditingOffset() > 0) { Node* childAtOffset = NodeTraversal::childAt(*startNode, pos.computeEditingOffset()); 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(createVisiblePosition(firstPositionInOrBeforeNode(startNode)), endingSelection().isDirectional())); return; } // Build up list of ancestors in between the start node and the top blockquote. WillBeHeapVector<RefPtrWillBeMember<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. RefPtrWillBeRawPtr<Element> clonedBlockquote = topBlockquote->cloneElementWithoutChildren(); insertNodeAfter(clonedBlockquote.get(), breakElement.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). RefPtrWillBeRawPtr<Element> clonedAncestor = clonedBlockquote; for (size_t i = ancestors.size(); i != 0; --i) { RefPtrWillBeRawPtr<Element> clonedChild = ancestors[i - 1]->cloneElementWithoutChildren(); // Preserve list item numbering in cloned lists. if (isHTMLOListElement(*clonedChild)) { 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 && !isHTMLLIElement(*listChildNode)) listChildNode = listChildNode->nextSibling(); if (isListItem(listChildNode)) setNodeAttribute(clonedChild, startAttr, AtomicString::number(toLayoutListItem(listChildNode->layoutObject())->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. RefPtrWillBeRawPtr<Element> ancestor = nullptr; RefPtrWillBeRawPtr<Element> clonedParent = nullptr; 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 Element* originalParent = ancestors.first().get(); if (!originalParent->hasChildren()) removeNode(originalParent); } // Make sure the cloned block quote renders. addBlockPlaceholderIfNeeded(clonedBlockquote.get()); // Put the selection right before the break. setEndingSelection(VisibleSelection(positionBeforeNode(breakElement.get()), TextAffinity::Downstream, endingSelection().isDirectional())); rebalanceWhitespace(); }