void CSSVariableResolver::resolveAndApplyVariableReferences(StyleResolverState& state, CSSPropertyID id, const CSSVariableReferenceValue& value)
{
    CSSVariableResolver resolver(state.style()->variables());

    Vector<CSSParserToken> tokens;
    if (resolver.resolveTokenRange(value.variableDataValue()->tokens(), tokens)) {
        CSSParserContext context(HTMLStandardMode, 0);

        HeapVector<CSSProperty, 256> parsedProperties;

        // TODO: Non-shorthands should just call CSSPropertyParser::parseSingleValue
        if (CSSPropertyParser::parseValue(id, false, CSSParserTokenRange(tokens), context, parsedProperties, StyleRule::RuleType::Style)) {
            unsigned parsedPropertiesCount = parsedProperties.size();
            for (unsigned i = 0; i < parsedPropertiesCount; ++i)
                StyleBuilder::applyProperty(parsedProperties[i].id(), state, parsedProperties[i].value());
            return;
        }
    }

    RawPtr<CSSUnsetValue> unset = cssValuePool().createUnsetValue();
    if (isShorthandProperty(id)) {
        StylePropertyShorthand shorthand = shorthandForProperty(id);
        for (unsigned i = 0; i < shorthand.length(); i++)
            StyleBuilder::applyProperty(shorthand.properties()[i], state, unset.get());
        return;
    }

    StyleBuilder::applyProperty(id, state, unset.get());
}
RawPtr<HTMLElement> VTTElement::createEquivalentHTMLElement(Document& document)
{
    RawPtr<HTMLElement> htmlElement = nullptr;
    switch (m_webVTTNodeType) {
    case VTTNodeTypeClass:
    case VTTNodeTypeLanguage:
    case VTTNodeTypeVoice:
        htmlElement = HTMLElementFactory::createHTMLElement(HTMLNames::spanTag.localName(), document);
        htmlElement.get()->setAttribute(HTMLNames::titleAttr, getAttribute(voiceAttributeName()));
        htmlElement.get()->setAttribute(HTMLNames::langAttr, getAttribute(langAttributeName()));
        break;
    case VTTNodeTypeItalic:
        htmlElement = HTMLElementFactory::createHTMLElement(HTMLNames::iTag.localName(), document);
        break;
    case VTTNodeTypeBold:
        htmlElement = HTMLElementFactory::createHTMLElement(HTMLNames::bTag.localName(), document);
        break;
    case VTTNodeTypeUnderline:
        htmlElement = HTMLElementFactory::createHTMLElement(HTMLNames::uTag.localName(), document);
        break;
    case VTTNodeTypeRuby:
        htmlElement = HTMLElementFactory::createHTMLElement(HTMLNames::rubyTag.localName(), document);
        break;
    case VTTNodeTypeRubyText:
        htmlElement = HTMLElementFactory::createHTMLElement(HTMLNames::rtTag.localName(), document);
        break;
    default:
        ASSERT_NOT_REACHED();
    }

    htmlElement.get()->setAttribute(HTMLNames::classAttr, getAttribute(HTMLNames::classAttr));
    return htmlElement;
}
// Tests moving extent over to the other side of the vase and immediately
// passing the word boundary and going into word granularity.
TEST_F(GranularityStrategyTest, DirectionSwitchSideWordGranularityThenShrink)
{
    dummyPageHolder().frame().settings()->setDefaultFontSize(12);
    String str = "ab cd efghijkl mnopqr iiin, abc";
    RawPtr<Text> text = document().createTextNode(str);
    document().body()->appendChild(text);
    dummyPageHolder().frame().settings()->setSelectionStrategy(SelectionStrategy::Direction);

    parseText(text.get());

    // "abcd efgh ijkl mno^pqr|> iiin, abc" (^ means base, | means extent, < means start, and > means end).
    selection().setSelection(VisibleSelection(Position(text, 18), Position(text, 21)));
    EXPECT_EQ_SELECTED_TEXT("pqr");
    // Move to the middle of word #4 selecting it - this will set the offset to
    // be half the width of "iiin".
    selection().moveRangeSelectionExtent(m_wordMiddles[4]);
    EXPECT_EQ_SELECTED_TEXT("pqr iiin");
    // Move to the middle of word #2 - extent will switch over to the other
    // side of the base, and we should enter word granularity since we pass
    // the word boundary. The offset should become negative since the width
    // of "efghjkkl" is greater than that of "iiin".
    int offset = m_letterPos[26].x() - m_wordMiddles[4].x();
    IntPoint p = IntPoint(m_wordMiddles[2].x() - offset - 1, m_wordMiddles[2].y());
    selection().moveRangeSelectionExtent(p);
    EXPECT_EQ_SELECTED_TEXT("efghijkl mno");
    p.move(m_letterPos[7].x() - m_letterPos[6].x(), 0);
    selection().moveRangeSelectionExtent(p);
    EXPECT_EQ_SELECTED_TEXT("fghijkl mno");
}
RawPtr<Text> Text::splitText(unsigned offset, ExceptionState& exceptionState)
{
    // IndexSizeError: Raised if the specified offset is negative or greater than
    // the number of 16-bit units in data.
    if (offset > length()) {
        exceptionState.throwDOMException(IndexSizeError, "The offset " + String::number(offset) + " is larger than the Text node's length.");
        return nullptr;
    }

    EventQueueScope scope;
    String oldStr = data();
    RawPtr<Text> newText = cloneWithData(oldStr.substring(offset));
    setDataWithoutUpdate(oldStr.substring(0, offset));

    didModifyData(oldStr, CharacterData::UpdateFromNonParser);

    if (parentNode())
        parentNode()->insertBefore(newText.get(), nextSibling(), exceptionState);
    if (exceptionState.hadException())
        return nullptr;

    if (layoutObject())
        layoutObject()->setTextWithOffset(dataImpl(), 0, oldStr.length());

    if (parentNode())
        document().didSplitTextNode(*this);

    return newText.release();
}
RawPtr<Text> GranularityStrategyTest::setupRotate(String str)
{
    setInnerHTML(
        "<html>"
        "<head>"
        "<style>"
            "div {"
                "transform: translate(0px,600px) rotate(90deg);"
            "}"
        "</style>"
        "</head>"
        "<body>"
        "<div id='mytext'></div>"
        "</body>"
        "</html>");

    RawPtr<Text> text = document().createTextNode(str);
    Element* div = document().getElementById("mytext");
    div->appendChild(text);

    document().view()->updateAllLifecyclePhases();

    parseText(text.get());
    return text.release();
}
WebRemoteFrame* WebRemoteFrameImpl::createRemoteChild(WebTreeScopeType scope, const WebString& name, const WebString& uniqueName, WebSandboxFlags sandboxFlags, WebRemoteFrameClient* client, WebFrame* opener)
{
    WebRemoteFrameImpl* child = WebRemoteFrameImpl::create(scope, client, opener);
    appendChild(child);
    RawPtr<RemoteFrameOwner> owner = RemoteFrameOwner::create(static_cast<SandboxFlags>(sandboxFlags), WebFrameOwnerProperties());
    child->initializeCoreFrame(frame()->host(), owner.get(), name, uniqueName);
    return child;
}
void BaseChooserOnlyDateAndTimeInputType::createShadowSubtree()
{
    DEFINE_STATIC_LOCAL(AtomicString, valueContainerPseudo, ("-webkit-date-and-time-value"));

    RawPtr<HTMLDivElement> valueContainer = HTMLDivElement::create(element().document());
    valueContainer->setShadowPseudoId(valueContainerPseudo);
    element().userAgentShadowRoot()->appendChild(valueContainer.get());
    updateView();
}
TEST_F(LayoutPartTest, DestroyUpdatesImageQualityController)
{
    RawPtr<Element> element = HTMLElement::create(HTMLNames::divTag, document());
    LayoutObject* part = new OverriddenLayoutPart(element.get());
    // The third and forth arguments are not important in this test.
    ImageQualityController::imageQualityController()->set(*part, 0, this, LayoutSize(1, 1), false);
    EXPECT_TRUE(ImageQualityController::has(*part));
    part->destroy();
    EXPECT_FALSE(ImageQualityController::has(*part));
}
TEST(MainThreadTaskRunnerTest, PostTask)
{
    RawPtr<NullExecutionContext> context = new NullExecutionContext();
    RawPtr<MainThreadTaskRunner> runner = MainThreadTaskRunner::create(context.get());
    bool isMarked = false;

    runner->postTask(BLINK_FROM_HERE, createSameThreadTask(&markBoolean, &isMarked));
    EXPECT_FALSE(isMarked);
    blink::testing::runPendingTasks();
    EXPECT_TRUE(isMarked);
}
void FileSystemCallbacksBase::handleEventOrScheduleCallback(RawPtr<CB> callback, CBArg* arg)
{
    ASSERT(callback);
    InspectorInstrumentationCookie cookie = InspectorInstrumentation::traceAsyncOperationCompletedCallbackStarting(m_executionContext.get(), m_asyncOperationId);
    if (shouldScheduleCallback())
        DOMFileSystem::scheduleCallback(m_executionContext.get(), callback.get(), arg);
    else if (callback)
        callback->handleEvent(arg);
    m_executionContext.clear();
    InspectorInstrumentation::traceAsyncCallbackCompleted(cookie);
}
TEST(MainThreadTaskRunnerTest, RemoveRunner)
{
    RawPtr<NullExecutionContext> context = new NullExecutionContext();
    RawPtr<MainThreadTaskRunner> runner = MainThreadTaskRunner::create(context.get());
    bool isMarked = false;

    context->setTasksNeedSuspension(true);
    runner->postTask(BLINK_FROM_HERE, createSameThreadTask(&markBoolean, &isMarked));
    runner.clear();
    blink::testing::runPendingTasks();
    EXPECT_FALSE(isMarked);
}
void DeviceSingleWindowEventController::dispatchDeviceEvent(RawPtr<Event> prpEvent)
{
    if (!document().domWindow() || document().activeDOMObjectsAreSuspended() || document().activeDOMObjectsAreStopped())
        return;

    RawPtr<Event> event = prpEvent;
    document().domWindow()->dispatchEvent(event);

    if (m_needsCheckingNullEvents) {
        if (isNullEvent(event.get()))
            stopUpdating();
        else
            m_needsCheckingNullEvents = false;
    }
}
WebLocalFrame* WebRemoteFrameImpl::createLocalChild(WebTreeScopeType scope, const WebString& name, const WebString& uniqueName, WebSandboxFlags sandboxFlags, WebFrameClient* client, WebFrame* previousSibling, const WebFrameOwnerProperties& frameOwnerProperties, WebFrame* opener)
{
    WebLocalFrameImpl* child = WebLocalFrameImpl::create(scope, client, opener);
    insertAfter(child, previousSibling);
    RawPtr<RemoteFrameOwner> owner = RemoteFrameOwner::create(static_cast<SandboxFlags>(sandboxFlags), frameOwnerProperties);
    // FIXME: currently this calls LocalFrame::init() on the created LocalFrame, which may
    // result in the browser observing two navigations to about:blank (one from the initial
    // frame creation, and one from swapping it into the remote process). FrameLoader might
    // need a special initialization function for this case to avoid that duplicate navigation.
    child->initializeCoreFrame(frame()->host(), owner.get(), name, uniqueName);
    // Partially related with the above FIXME--the init() call may trigger JS dispatch. However,
    // if the parent is remote, it should never be detached synchronously...
    DCHECK(child->frame());
    return child;
}
static void verifyCSSCalc(String text, double value, bool valid, unsigned fontSize, unsigned viewportWidth, unsigned viewportHeight)
{
    CSSLengthArray lengthArray;
    initLengthArray(lengthArray);
    RawPtr<CSSValue> cssValue = CSSParser::parseSingleValue(CSSPropertyLeft, text);
    CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(cssValue.get());
    if (primitiveValue)
        primitiveValue->accumulateLengthArray(lengthArray);
    else
        ASSERT_EQ(valid, false);
    float length = lengthArray.at(CSSPrimitiveValue::UnitTypePixels);
    length += lengthArray.at(CSSPrimitiveValue::UnitTypeFontSize) * fontSize;
    length += lengthArray.at(CSSPrimitiveValue::UnitTypeViewportWidth) * viewportWidth / 100.0;
    length += lengthArray.at(CSSPrimitiveValue::UnitTypeViewportHeight) * viewportHeight / 100.0;
    ASSERT_EQ(value, length);
}
void ConsoleMessageStorage::reportMessage(ExecutionContext* context, RawPtr<ConsoleMessage> prpMessage)
{
    RawPtr<ConsoleMessage> message = prpMessage;
    message->collectCallStack();

    if (message->type() == ClearMessageType)
        clear(context);

    InspectorInstrumentation::addMessageToConsole(context, message.get());

    ASSERT(m_messages.size() <= maxConsoleMessageCount);
    if (m_messages.size() == maxConsoleMessageCount) {
        ++m_expiredCount;
        m_messages.removeFirst();
    }
    m_messages.append(message);
}
// Make sure we switch to word granularity right away when starting on a
// word boundary and extending.
TEST_F(GranularityStrategyTest, DirectionSwitchStartOnBoundary)
{
    dummyPageHolder().frame().settings()->setDefaultFontSize(12);
    String str = "ab cd efghijkl mnopqr iiin, abc";
    RawPtr<Text> text = document().createTextNode(str);
    document().body()->appendChild(text);
    dummyPageHolder().frame().settings()->setSelectionStrategy(SelectionStrategy::Direction);

    parseText(text.get());

    // "ab cd efghijkl ^mnopqr |>stuvwi inm," (^ means base and | means extent,
    // > means end).
    selection().setSelection(VisibleSelection(Position(text, 15), Position(text, 22)));
    EXPECT_EQ_SELECTED_TEXT("mnopqr ");
    selection().moveRangeSelectionExtent(m_wordMiddles[4]);
    EXPECT_EQ_SELECTED_TEXT("mnopqr iiin");
}
WebDOMMessageEvent::WebDOMMessageEvent(const WebSerializedScriptValue& messageData, const WebString& origin, const WebFrame* sourceFrame, const WebDocument& targetDocument, const WebMessagePortChannelArray& channels)
    : WebDOMMessageEvent(MessageEvent::create())
{
    DOMWindow* window = nullptr;
    if (sourceFrame)
        window = sourceFrame->toImplBase()->frame()->domWindow();
    MessagePortArray* ports = nullptr;
    if (!targetDocument.isNull()) {
        RawPtr<Document> coreDocument = RawPtr<Document>(targetDocument);
        ports = MessagePort::toMessagePortArray(coreDocument.get(), channels);
    }
    // Use an empty array for |ports| when it is null because this function
    // is used to implement postMessage().
    if (!ports)
        ports = new MessagePortArray;
    // TODO(esprehn): Chromium always passes empty string for lastEventId, is that right?
    unwrap<MessageEvent>()->initMessageEvent("message", false, false, messageData, origin, ""/*lastEventId*/, window, ports);
}
void InsertParagraphSeparatorCommand::doApply(EditingState* editingState)
{
    if (!endingSelection().isNonOrphanedCaretOrRange())
        return;

    Position insertionPosition = endingSelection().start();

    TextAffinity affinity = endingSelection().affinity();

    // Delete the current selection.
    if (endingSelection().isRange()) {
        calculateStyleBeforeInsertion(insertionPosition);
        deleteSelection(editingState, false, true);
        if (editingState->isAborted())
            return;
        insertionPosition = endingSelection().start();
        affinity = endingSelection().affinity();
    }

    // FIXME: The parentAnchoredEquivalent conversion needs to be moved into enclosingBlock.
    RawPtr<Element> startBlock = enclosingBlock(insertionPosition.parentAnchoredEquivalent().computeContainerNode());
    Node* listChildNode = enclosingListChild(insertionPosition.parentAnchoredEquivalent().computeContainerNode());
    RawPtr<HTMLElement> listChild = listChildNode && listChildNode->isHTMLElement() ? toHTMLElement(listChildNode) : 0;
    Position canonicalPos = createVisiblePosition(insertionPosition).deepEquivalent();
    if (!startBlock
        || !startBlock->nonShadowBoundaryParentNode()
        || isTableCell(startBlock.get())
        || isHTMLFormElement(*startBlock)
        // FIXME: If the node is hidden, we don't have a canonical position so we will do the wrong thing for tables and <hr>. https://bugs.webkit.org/show_bug.cgi?id=40342
        || (!canonicalPos.isNull() && isDisplayInsideTable(canonicalPos.anchorNode()))
        || (!canonicalPos.isNull() && isHTMLHRElement(*canonicalPos.anchorNode()))) {
        applyCommandToComposite(InsertLineBreakCommand::create(document()), editingState);
        return;
    }

    // Use the leftmost candidate.
    insertionPosition = mostBackwardCaretPosition(insertionPosition);
    if (!isVisuallyEquivalentCandidate(insertionPosition))
        insertionPosition = mostForwardCaretPosition(insertionPosition);

    // Adjust the insertion position after the delete
    const Position originalInsertionPosition = insertionPosition;
    const Element* enclosingAnchor = enclosingAnchorElement(originalInsertionPosition);
    insertionPosition = positionAvoidingSpecialElementBoundary(insertionPosition, editingState);
    if (editingState->isAborted())
        return;
    if (listChild == enclosingAnchor) {
        // |positionAvoidingSpecialElementBoundary()| creates new A element and
        // move to another place.
        listChild = toHTMLElement(enclosingAnchorElement(originalInsertionPosition));
    }
    VisiblePosition visiblePos = createVisiblePosition(insertionPosition, affinity);
    calculateStyleBeforeInsertion(insertionPosition);

    //---------------------------------------------------------------------
    // Handle special case of typing return on an empty list item
    if (breakOutOfEmptyListItem(editingState) || editingState->isAborted())
        return;

    //---------------------------------------------------------------------
    // Prepare for more general cases.

    bool isFirstInBlock = isStartOfBlock(visiblePos);
    bool isLastInBlock = isEndOfBlock(visiblePos);
    bool nestNewBlock = false;

    // Create block to be inserted.
    RawPtr<Element> blockToInsert = nullptr;
    if (startBlock->isRootEditableElement()) {
        blockToInsert = createDefaultParagraphElement(document());
        nestNewBlock = true;
    } else if (shouldUseDefaultParagraphElement(startBlock.get())) {
        blockToInsert = createDefaultParagraphElement(document());
    } else {
        blockToInsert = startBlock->cloneElementWithoutChildren();
    }

    //---------------------------------------------------------------------
    // Handle case when position is in the last visible position in its block,
    // including when the block is empty.
    if (isLastInBlock) {
        if (nestNewBlock) {
            if (isFirstInBlock && !lineBreakExistsAtVisiblePosition(visiblePos)) {
                // The block is empty.  Create an empty block to
                // represent the paragraph that we're leaving.
                RawPtr<HTMLElement> extraBlock = createDefaultParagraphElement(document());
                appendNode(extraBlock, startBlock, editingState);
                if (editingState->isAborted())
                    return;
                appendBlockPlaceholder(extraBlock, editingState);
                if (editingState->isAborted())
                    return;
            }
            appendNode(blockToInsert, startBlock, editingState);
            if (editingState->isAborted())
                return;
        } else {
            // We can get here if we pasted a copied portion of a blockquote with a newline at the end and are trying to paste it
            // into an unquoted area. We then don't want the newline within the blockquote or else it will also be quoted.
            if (m_pasteBlockquoteIntoUnquotedArea) {
                if (HTMLQuoteElement* highestBlockquote = toHTMLQuoteElement(highestEnclosingNodeOfType(canonicalPos, &isMailHTMLBlockquoteElement)))
                    startBlock = highestBlockquote;
            }

            if (listChild && listChild != startBlock) {
                RawPtr<Element> listChildToInsert = listChild->cloneElementWithoutChildren();
                appendNode(blockToInsert, listChildToInsert.get(), editingState);
                if (editingState->isAborted())
                    return;
                insertNodeAfter(listChildToInsert.get(), listChild, editingState);
            } else {
                // Most of the time we want to stay at the nesting level of the startBlock (e.g., when nesting within lists). However,
                // for div nodes, this can result in nested div tags that are hard to break out of.
                Element* siblingElement = startBlock.get();
                if (isHTMLDivElement(*blockToInsert))
                    siblingElement = highestVisuallyEquivalentDivBelowRoot(startBlock.get());
                insertNodeAfter(blockToInsert, siblingElement, editingState);
            }
            if (editingState->isAborted())
                return;
        }

        // Recreate the same structure in the new paragraph.

        HeapVector<Member<Element>> ancestors;
        getAncestorsInsideBlock(positionOutsideTabSpan(insertionPosition).anchorNode(), startBlock.get(), ancestors);
        RawPtr<Element> parent = cloneHierarchyUnderNewBlock(ancestors, blockToInsert, editingState);
        if (editingState->isAborted())
            return;

        appendBlockPlaceholder(parent, editingState);
        if (editingState->isAborted())
            return;

        setEndingSelection(VisibleSelection(firstPositionInNode(parent.get()), TextAffinity::Downstream, endingSelection().isDirectional()));
        return;
    }


    //---------------------------------------------------------------------
    // Handle case when position is in the first visible position in its block, and
    // similar case where previous position is in another, presumeably nested, block.
    if (isFirstInBlock || !inSameBlock(visiblePos, previousPositionOf(visiblePos))) {
        Node* refNode = nullptr;
        insertionPosition = positionOutsideTabSpan(insertionPosition);

        if (isFirstInBlock && !nestNewBlock) {
            if (listChild && listChild != startBlock) {
                RawPtr<Element> listChildToInsert = listChild->cloneElementWithoutChildren();
                appendNode(blockToInsert, listChildToInsert.get(), editingState);
                if (editingState->isAborted())
                    return;
                insertNodeBefore(listChildToInsert.get(), listChild, editingState);
                if (editingState->isAborted())
                    return;
            } else {
                refNode = startBlock.get();
            }
        } else if (isFirstInBlock && nestNewBlock) {
            // startBlock should always have children, otherwise isLastInBlock would be true and it's handled above.
            ASSERT(startBlock->hasChildren());
            refNode = startBlock->firstChild();
        } else if (insertionPosition.anchorNode() == startBlock && nestNewBlock) {
            refNode = NodeTraversal::childAt(*startBlock, insertionPosition.computeEditingOffset());
            ASSERT(refNode); // must be true or we'd be in the end of block case
        } else {
            refNode = insertionPosition.anchorNode();
        }

        // find ending selection position easily before inserting the paragraph
        insertionPosition = mostForwardCaretPosition(insertionPosition);

        if (refNode) {
            insertNodeBefore(blockToInsert, refNode, editingState);
            if (editingState->isAborted())
                return;
        }

        // Recreate the same structure in the new paragraph.

        HeapVector<Member<Element>> ancestors;
        insertionPosition = positionAvoidingSpecialElementBoundary(positionOutsideTabSpan(insertionPosition), editingState);
        if (editingState->isAborted())
            return;
        getAncestorsInsideBlock(insertionPosition.anchorNode(), startBlock.get(), ancestors);

        RawPtr<Element> placeholder = cloneHierarchyUnderNewBlock(ancestors, blockToInsert, editingState);
        if (editingState->isAborted())
            return;
        appendBlockPlaceholder(placeholder.release(), editingState);
        if (editingState->isAborted())
            return;

        // In this case, we need to set the new ending selection.
        setEndingSelection(VisibleSelection(insertionPosition, TextAffinity::Downstream, endingSelection().isDirectional()));
        return;
    }

    //---------------------------------------------------------------------
    // Handle the (more complicated) general case,

    // All of the content in the current block after visiblePos is
    // about to be wrapped in a new paragraph element.  Add a br before
    // it if visiblePos is at the start of a paragraph so that the
    // content will move down a line.
    if (isStartOfParagraph(visiblePos)) {
        RawPtr<HTMLBRElement> br = HTMLBRElement::create(document());
        insertNodeAt(br.get(), insertionPosition, editingState);
        if (editingState->isAborted())
            return;
        insertionPosition = positionInParentAfterNode(*br);
        // If the insertion point is a break element, there is nothing else
        // we need to do.
        if (visiblePos.deepEquivalent().anchorNode()->layoutObject()->isBR()) {
            setEndingSelection(VisibleSelection(insertionPosition, TextAffinity::Downstream, endingSelection().isDirectional()));
            return;
        }
    }

    // Move downstream. Typing style code will take care of carrying along the
    // style of the upstream position.
    insertionPosition = mostForwardCaretPosition(insertionPosition);

    // At this point, the insertionPosition's node could be a container, and we want to make sure we include
    // all of the correct nodes when building the ancestor list.  So this needs to be the deepest representation of the position
    // before we walk the DOM tree.
    insertionPosition = positionOutsideTabSpan(createVisiblePosition(insertionPosition).deepEquivalent());

    // If the returned position lies either at the end or at the start of an element that is ignored by editing
    // we should move to its upstream or downstream position.
    if (editingIgnoresContent(insertionPosition.anchorNode())) {
        if (insertionPosition.atLastEditingPositionForNode())
            insertionPosition = mostForwardCaretPosition(insertionPosition);
        else if (insertionPosition.atFirstEditingPositionForNode())
            insertionPosition = mostBackwardCaretPosition(insertionPosition);
    }

    // Make sure we do not cause a rendered space to become unrendered.
    // FIXME: We need the affinity for pos, but mostForwardCaretPosition does not give it
    Position leadingWhitespace = leadingWhitespacePosition(insertionPosition, VP_DEFAULT_AFFINITY);
    // FIXME: leadingWhitespacePosition is returning the position before preserved newlines for positions
    // after the preserved newline, causing the newline to be turned into a nbsp.
    if (leadingWhitespace.isNotNull() && leadingWhitespace.anchorNode()->isTextNode()) {
        Text* textNode = toText(leadingWhitespace.anchorNode());
        ASSERT(!textNode->layoutObject() || textNode->layoutObject()->style()->collapseWhiteSpace());
        replaceTextInNodePreservingMarkers(textNode, leadingWhitespace.computeOffsetInContainerNode(), 1, nonBreakingSpaceString());
    }

    // Split at pos if in the middle of a text node.
    Position positionAfterSplit;
    if (insertionPosition.isOffsetInAnchor() && insertionPosition.computeContainerNode()->isTextNode()) {
        RawPtr<Text> textNode = toText(insertionPosition.computeContainerNode());
        int textOffset = insertionPosition.offsetInContainerNode();
        bool atEnd = static_cast<unsigned>(textOffset) >= textNode->length();
        if (textOffset > 0 && !atEnd) {
            splitTextNode(textNode, textOffset);
            positionAfterSplit = firstPositionInNode(textNode.get());
            insertionPosition = Position(textNode->previousSibling(), textOffset);
            visiblePos = createVisiblePosition(insertionPosition);
        }
    }

    // If we got detached due to mutation events, just bail out.
    if (!startBlock->parentNode())
        return;

    // Put the added block in the tree.
    if (nestNewBlock) {
        appendNode(blockToInsert.get(), startBlock, editingState);
    } else if (listChild && listChild != startBlock) {
        RawPtr<Element> listChildToInsert = listChild->cloneElementWithoutChildren();
        appendNode(blockToInsert.get(), listChildToInsert.get(), editingState);
        if (editingState->isAborted())
            return;
        insertNodeAfter(listChildToInsert.get(), listChild, editingState);
    } else {
        insertNodeAfter(blockToInsert.get(), startBlock, editingState);
    }
    if (editingState->isAborted())
        return;

    document().updateLayoutIgnorePendingStylesheets();

    // If the paragraph separator was inserted at the end of a paragraph, an empty line must be
    // created.  All of the nodes, starting at visiblePos, are about to be added to the new paragraph
    // element.  If the first node to be inserted won't be one that will hold an empty line open, add a br.
    if (isEndOfParagraph(visiblePos) && !lineBreakExistsAtVisiblePosition(visiblePos)) {
        appendNode(HTMLBRElement::create(document()).get(), blockToInsert.get(), editingState);
        if (editingState->isAborted())
            return;
    }

    // Move the start node and the siblings of the start node.
    if (createVisiblePosition(insertionPosition).deepEquivalent() != createVisiblePosition(positionBeforeNode(blockToInsert.get())).deepEquivalent()) {
        Node* n;
        if (insertionPosition.computeContainerNode() == startBlock) {
            n = insertionPosition.computeNodeAfterPosition();
        } else {
            Node* splitTo = insertionPosition.computeContainerNode();
            if (splitTo->isTextNode() && insertionPosition.offsetInContainerNode() >= caretMaxOffset(splitTo))
                splitTo = NodeTraversal::next(*splitTo, startBlock.get());
            if (splitTo)
                splitTreeToNode(splitTo, startBlock.get());

            for (n = startBlock->firstChild(); n; n = n->nextSibling()) {
                VisiblePosition beforeNodePosition = createVisiblePosition(positionBeforeNode(n));
                if (!beforeNodePosition.isNull() && comparePositions(createVisiblePosition(insertionPosition), beforeNodePosition) <= 0)
                    break;
            }
        }

        moveRemainingSiblingsToNewParent(n, blockToInsert.get(), blockToInsert, editingState);
        if (editingState->isAborted())
            return;
    }

    // Handle whitespace that occurs after the split
    if (positionAfterSplit.isNotNull()) {
        document().updateLayoutIgnorePendingStylesheets();
        // TODO(yosin) |isRenderedCharacter()| should be removed, and we should
        // use |VisiblePosition::characterAfter()|.
        if (!isRenderedCharacter(positionAfterSplit)) {
            // Clear out all whitespace and insert one non-breaking space
            ASSERT(!positionAfterSplit.computeContainerNode()->layoutObject() || positionAfterSplit.computeContainerNode()->layoutObject()->style()->collapseWhiteSpace());
            deleteInsignificantTextDownstream(positionAfterSplit);
            if (positionAfterSplit.anchorNode()->isTextNode())
                insertTextIntoNode(toText(positionAfterSplit.computeContainerNode()), 0, nonBreakingSpaceString());
        }
    }

    setEndingSelection(VisibleSelection(firstPositionInNode(blockToInsert.get()), TextAffinity::Downstream, endingSelection().isDirectional()));
    applyStyleAfterInsertion(startBlock.get(), editingState);
}
TEST_F(ContextMenuControllerTest, TestCustomMenu)
{
    document().settings()->setScriptEnabled(true);
    // Load the the test page.
    setBodyInnerHTML(
        "<button id=\"button_id\" contextmenu=\"menu_id\" style=\"height: 100px; width: 100px;\">"
        "<menu type=\"context\" id=\"menu_id\">"
        "<menuitem label=\"Item1\" onclick='document.title = \"Title 1\";'>"
        "<menuitem label=\"Item2\" onclick='document.title = \"Title 2\";'>"
        "<menuitem label=\"Item3\" onclick='document.title = \"Title 3\";'>"
        "<menu label='Submenu'>"
        "<menuitem label=\"Item4\" onclick='document.title = \"Title 4\";'>"
        "<menuitem label=\"Item5\" onclick='document.title = \"Title 5\";'>"
        "<menuitem label=\"Item6\" onclick='document.title = \"Title 6\";'>"
        "</menu>"
        "<menuitem id=\"item7\" type=\"checkbox\" checked label=\"Item7\""
        "onclick='if (document.getElementById(\"item7\").hasAttribute(\"checked\"))"
        "document.title = \"Title 7 checked\"; else document.title = \"Title 7 not checked\";'>"
        "<menuitem id=\"item8\" type=\"radio\" radiogroup=\"group\" label=\"Item8\""
        "onclick='if (document.getElementById(\"item8\").hasAttribute(\"checked\"))"
        "document.title = \"Title 8 checked\"; else if (document.getElementById(\"item9\").hasAttribute(\"checked\"))"
        "document.title = \"Title 8 not checked and Title 9 checked\";'>"
        "<menuitem id=\"item9\" type=\"radio\" radiogroup=\"group\" checked label=\"Item9\""
        "onclick='if (document.getElementById(\"item9\").hasAttribute(\"checked\"))"
        "document.title = \"Title 9 checked\"; else document.title = \"Title 9 not checked\";'>"
        "<menuitem id=\"item10\" type=\"radio\" radiogroup=\"group\" label=\"Item10\""
        "onclick='if (document.getElementById(\"item10\").hasAttribute(\"checked\"))"
        "document.title = \"Title 10 checked\"; else if (document.getElementById(\"item8\").hasAttribute(\"checked\"))"
        "document.title = \"Title 10 not checked and Title 8 checked\";'>"
        "</menu>"
        "</button>");

    // Create right button click event and pass it to context menu controller.
    RawPtr<Event> event = MouseEvent::create(EventTypeNames::click, false, false,
        document().domWindow(), 50, 50, 0, 0, 0, 0, 0, PlatformEvent::NoModifiers, 1, 0, nullptr, 0,
        PlatformMouseEvent::RealOrIndistinguishable, String());
    document().getElementById("button_id")->focus();
    event->setTarget(document().getElementById("button_id"));
    document().page()->contextMenuController().handleContextMenuEvent(event.get());

    // Item 1
    // Item 2
    // Item 3
    // Submenu > Item 4
    //           Item 5
    //           Item 6
    // *Item 7
    // Item 8
    // *Item 9
    // Item 10
    const Vector<ContextMenuItem>& items = document().page()->contextMenuController().contextMenu()->items();
    EXPECT_EQ(8u, items.size());
    EXPECT_EQ(ActionType, items[0].type());
    EXPECT_STREQ("Item1", items[0].title().utf8().data());
    document().page()->contextMenuController().contextMenuItemSelected(&items[0]);
    EXPECT_STREQ("Title 1", document().title().utf8().data());
    EXPECT_EQ(SubmenuType, items[3].type());
    EXPECT_STREQ("Submenu", items[3].title().utf8().data());
    const Vector<ContextMenuItem>& subMenuItems = items[3].subMenuItems();
    EXPECT_EQ(3u, subMenuItems.size());
    EXPECT_STREQ("Item6", subMenuItems[2].title().utf8().data());
    document().page()->contextMenuController().contextMenuItemSelected(&subMenuItems[2]);
    EXPECT_STREQ("Title 6", document().title().utf8().data());
    document().page()->contextMenuController().contextMenuItemSelected(&items[4]);
    EXPECT_STREQ("Title 7 checked", document().title().utf8().data());
    document().page()->contextMenuController().contextMenuItemSelected(&items[4]);
    EXPECT_STREQ("Title 7 not checked", document().title().utf8().data());
    document().page()->contextMenuController().contextMenuItemSelected(&items[5]);
    EXPECT_STREQ("Title 8 not checked and Title 9 checked", document().title().utf8().data());
    document().page()->contextMenuController().contextMenuItemSelected(&items[7]);
    EXPECT_STREQ("Title 10 not checked and Title 8 checked", document().title().utf8().data());
}
void V8MutationObserver::constructorCustom(const v8::FunctionCallbackInfo<v8::Value>& info)
{
    ExceptionState exceptionState(ExceptionState::ConstructionContext, "MutationObserver", info.Holder(), info.GetIsolate());
    if (info.Length() < 1) {
        exceptionState.throwTypeError(ExceptionMessages::notEnoughArguments(1, info.Length()));
        exceptionState.throwIfNeeded();
        return;
    }

    v8::Local<v8::Value> arg = info[0];
    if (!arg->IsFunction()) {
        exceptionState.throwTypeError("Callback argument must be a function");
        exceptionState.throwIfNeeded();
        return;
    }

    v8::Local<v8::Object> wrapper = info.Holder();

    RawPtr<MutationCallback> callback = V8MutationCallback::create(v8::Local<v8::Function>::Cast(arg), wrapper, ScriptState::current(info.GetIsolate()));
    RawPtr<MutationObserver> observer = MutationObserver::create(callback.release());

    v8SetReturnValue(info, V8DOMWrapper::associateObjectWithWrapper(info.GetIsolate(), observer.get(), &wrapperTypeInfo, wrapper));
}
void InputMethodController::setComposition(const String& text, const Vector<CompositionUnderline>& underlines, unsigned selectionStart, unsigned selectionEnd)
{
    Editor::RevealSelectionScope revealSelectionScope(&editor());

    // Updates styles before setting selection for composition to prevent
    // inserting the previous composition text into text nodes oddly.
    // See https://bugs.webkit.org/show_bug.cgi?id=46868
    frame().document()->updateLayoutTree();

    selectComposition();

    if (frame().selection().isNone())
        return;

    if (Element* target = frame().document()->focusedElement()) {
        // Dispatch an appropriate composition event to the focused node.
        // We check the composition status and choose an appropriate composition event since this
        // function is used for three purposes:
        // 1. Starting a new composition.
        //    Send a compositionstart and a compositionupdate event when this function creates
        //    a new composition node, i.e.
        //    !hasComposition() && !text.isEmpty().
        //    Sending a compositionupdate event at this time ensures that at least one
        //    compositionupdate event is dispatched.
        // 2. Updating the existing composition node.
        //    Send a compositionupdate event when this function updates the existing composition
        //    node, i.e. hasComposition() && !text.isEmpty().
        // 3. Canceling the ongoing composition.
        //    Send a compositionend event when function deletes the existing composition node, i.e.
        //    !hasComposition() && test.isEmpty().
        RawPtr<CompositionEvent> event = nullptr;
        if (!hasComposition()) {
            // We should send a compositionstart event only when the given text is not empty because this
            // function doesn't create a composition node when the text is empty.
            if (!text.isEmpty()) {
                target->dispatchEvent(CompositionEvent::create(EventTypeNames::compositionstart, frame().domWindow(), frame().selectedText()));
                event = CompositionEvent::create(EventTypeNames::compositionupdate, frame().domWindow(), text);
            }
        } else {
            if (!text.isEmpty())
                event = CompositionEvent::create(EventTypeNames::compositionupdate, frame().domWindow(), text);
            else
                event = CompositionEvent::create(EventTypeNames::compositionend, frame().domWindow(), text);
        }
        if (event.get())
            target->dispatchEvent(event);
    }

    // If text is empty, then delete the old composition here. If text is non-empty, InsertTextCommand::input
    // will delete the old composition with an optimized replace operation.
    if (text.isEmpty()) {
        ASSERT(frame().document());
        TypingCommand::deleteSelection(*frame().document(), TypingCommand::PreventSpellChecking);
    }

    clear();

    if (text.isEmpty())
        return;
    ASSERT(frame().document());
    TypingCommand::insertText(*frame().document(), text, TypingCommand::SelectInsertedText | TypingCommand::PreventSpellChecking, TypingCommand::TextCompositionUpdate);

    // Find out what node has the composition now.
    Position base = mostForwardCaretPosition(frame().selection().base());
    Node* baseNode = base.anchorNode();
    if (!baseNode || !baseNode->isTextNode())
        return;

    Position extent = frame().selection().extent();
    Node* extentNode = extent.anchorNode();
    if (baseNode != extentNode)
        return;

    unsigned extentOffset = extent.computeOffsetInContainerNode();
    unsigned baseOffset = base.computeOffsetInContainerNode();
    if (baseOffset + text.length() != extentOffset)
        return;

    m_isDirty = true;
    m_hasComposition = true;
    if (!m_compositionRange)
        m_compositionRange = Range::create(baseNode->document());
    m_compositionRange->setStart(baseNode, baseOffset);
    m_compositionRange->setEnd(baseNode, extentOffset);

    if (baseNode->layoutObject())
        baseNode->layoutObject()->setShouldDoFullPaintInvalidation();

    unsigned start = std::min(baseOffset + selectionStart, extentOffset);
    unsigned end = std::min(std::max(start, baseOffset + selectionEnd), extentOffset);
    RawPtr<Range> selectedRange = Range::create(baseNode->document(), baseNode, start, baseNode, end);
    frame().selection().setSelectedRange(selectedRange.get(), TextAffinity::Downstream, SelectionDirectionalMode::NonDirectional, NotUserTriggered);

    if (underlines.isEmpty()) {
        frame().document()->markers().addCompositionMarker(m_compositionRange->startPosition(), m_compositionRange->endPosition(), Color::black, false, LayoutTheme::theme().platformDefaultCompositionBackgroundColor());
        return;
    }
    for (const auto& underline : underlines) {
        unsigned underlineStart = baseOffset + underline.startOffset;
        unsigned underlineEnd = baseOffset + underline.endOffset;
        EphemeralRange ephemeralLineRange = EphemeralRange(Position(baseNode, underlineStart), Position(baseNode, underlineEnd));
        if (ephemeralLineRange.isNull())
            continue;
        frame().document()->markers().addCompositionMarker(ephemeralLineRange.startPosition(), ephemeralLineRange.endPosition(), underline.color, underline.thick, underline.backgroundColor);
    }
}
FilterOperations FilterOperationResolver::createFilterOperations(StyleResolverState& state, const CSSValue& inValue)
{
    FilterOperations operations;

    if (inValue.isPrimitiveValue()) {
        ASSERT(toCSSPrimitiveValue(inValue).getValueID() == CSSValueNone);
        return operations;
    }

    const CSSToLengthConversionData& conversionData = state.cssToLengthConversionData();
    for (auto& currValue : toCSSValueList(inValue)) {
        CSSFunctionValue* filterValue = toCSSFunctionValue(currValue.get());
        FilterOperation::OperationType operationType = filterOperationForType(filterValue->functionType());
        countFilterUse(operationType, state.document());
        ASSERT(filterValue->length() <= 1);

        if (operationType == FilterOperation::REFERENCE) {
            CSSSVGDocumentValue* svgDocumentValue = toCSSSVGDocumentValue(filterValue->item(0));
            KURL url = state.document().completeURL(svgDocumentValue->url());

            RawPtr<ReferenceFilterOperation> operation = ReferenceFilterOperation::create(svgDocumentValue->url(), AtomicString(url.fragmentIdentifier()));
            if (SVGURIReference::isExternalURIReference(svgDocumentValue->url(), state.document())) {
                if (!svgDocumentValue->loadRequested())
                    state.elementStyleResources().addPendingSVGDocument(operation.get(), svgDocumentValue);
                else if (svgDocumentValue->cachedSVGDocument())
                    ReferenceFilterBuilder::setDocumentResourceReference(operation.get(), adoptPtr(new DocumentResourceReference(svgDocumentValue->cachedSVGDocument())));
            }
            operations.operations().append(operation);
            continue;
        }

        CSSPrimitiveValue* firstValue = filterValue->length() && filterValue->item(0)->isPrimitiveValue() ? toCSSPrimitiveValue(filterValue->item(0)) : nullptr;
        switch (filterValue->functionType()) {
        case CSSValueGrayscale:
        case CSSValueSepia:
        case CSSValueSaturate: {
            double amount = 1;
            if (filterValue->length() == 1) {
                amount = firstValue->getDoubleValue();
                if (firstValue->isPercentage())
                    amount /= 100;
            }

            operations.operations().append(BasicColorMatrixFilterOperation::create(amount, operationType));
            break;
        }
        case CSSValueHueRotate: {
            double angle = 0;
            if (filterValue->length() == 1)
                angle = firstValue->computeDegrees();

            operations.operations().append(BasicColorMatrixFilterOperation::create(angle, operationType));
            break;
        }
        case CSSValueInvert:
        case CSSValueBrightness:
        case CSSValueContrast:
        case CSSValueOpacity: {
            double amount = (filterValue->functionType() == CSSValueBrightness) ? 0 : 1;
            if (filterValue->length() == 1) {
                amount = firstValue->getDoubleValue();
                if (firstValue->isPercentage())
                    amount /= 100;
            }

            operations.operations().append(BasicComponentTransferFilterOperation::create(amount, operationType));
            break;
        }
        case CSSValueBlur: {
            Length stdDeviation = Length(0, Fixed);
            if (filterValue->length() >= 1)
                stdDeviation = firstValue->convertToLength(conversionData);
            operations.operations().append(BlurFilterOperation::create(stdDeviation));
            break;
        }
        case CSSValueDropShadow: {
            CSSShadowValue* item = toCSSShadowValue(filterValue->item(0));
            IntPoint location(item->x->computeLength<int>(conversionData), item->y->computeLength<int>(conversionData));
            int blur = item->blur ? item->blur->computeLength<int>(conversionData) : 0;
            Color shadowColor = Color::black;
            if (item->color)
                shadowColor = state.document().textLinkColors().colorFromCSSValue(*item->color, state.style()->color());

            operations.operations().append(DropShadowFilterOperation::create(location, blur, shadowColor));
            break;
        }
        default:
            ASSERT_NOT_REACHED();
            break;
        }
    }

    return operations;
}