void ScriptedAnimationController::dispatchEvents(const AtomicString& eventInterfaceFilter)
{
    WillBeHeapVector<RefPtrWillBeMember<Event> > events;
    if (eventInterfaceFilter.isEmpty()) {
        events.swap(m_eventQueue);
        m_perFrameEvents.clear();
    } else {
        WillBeHeapVector<RefPtrWillBeMember<Event> > remaining;
        for (auto& event : m_eventQueue) {
            if (event && event->interfaceName() == eventInterfaceFilter) {
                m_perFrameEvents.remove(eventTargetKey(event.get()));
                events.append(event.release());
            } else {
                remaining.append(event.release());
            }
        }
        remaining.swap(m_eventQueue);
    }


    for (size_t i = 0; i < events.size(); ++i) {
        EventTarget* eventTarget = events[i]->target();
        // FIXME: we should figure out how to make dispatchEvent properly virtual to avoid
        // special casting window.
        // FIXME: We should not fire events for nodes that are no longer in the tree.
        if (LocalDOMWindow* window = eventTarget->toDOMWindow())
            window->dispatchEvent(events[i], nullptr);
        else
            eventTarget->dispatchEvent(events[i]);

        InspectorInstrumentation::didRemoveEvent(eventTarget, events[i].get());
    }
}
inline static PassRefPtrWillBeRawPtr<AnimatableValue> createFromFillLayers(const FillLayer& fillLayers, const RenderStyle& style)
{
    WillBeHeapVector<RefPtrWillBeMember<AnimatableValue> > values;
    for (const FillLayer* fillLayer = &fillLayers; fillLayer; fillLayer = fillLayer->next()) {
        if (property == CSSPropertyBackgroundImage || property == CSSPropertyWebkitMaskImage) {
            if (!fillLayer->isImageSet())
                break;
            values.append(createFromStyleImage(fillLayer->image()));
        } else if (property == CSSPropertyBackgroundPositionX || property == CSSPropertyWebkitMaskPositionX) {
            if (!fillLayer->isXPositionSet())
                break;
            values.append(createFromBackgroundPosition(fillLayer->xPosition(), fillLayer->isBackgroundXOriginSet(), fillLayer->backgroundXOrigin(), style));
        } else if (property == CSSPropertyBackgroundPositionY || property == CSSPropertyWebkitMaskPositionY) {
            if (!fillLayer->isYPositionSet())
                break;
            values.append(createFromBackgroundPosition(fillLayer->yPosition(), fillLayer->isBackgroundYOriginSet(), fillLayer->backgroundYOrigin(), style));
        } else if (property == CSSPropertyBackgroundSize || property == CSSPropertyWebkitMaskSize) {
            if (!fillLayer->isSizeSet())
                break;
            values.append(createFromFillSize(fillLayer->size(), style));
        } else {
            ASSERT_NOT_REACHED();
        }
    }
    return AnimatableRepeatable::create(values);
}
void EventPath::adjustForTouchEvent(TouchEvent& touchEvent)
{
    WillBeHeapVector<RawPtrWillBeMember<TouchList>> adjustedTouches;
    WillBeHeapVector<RawPtrWillBeMember<TouchList>> adjustedTargetTouches;
    WillBeHeapVector<RawPtrWillBeMember<TouchList>> adjustedChangedTouches;
    WillBeHeapVector<RawPtrWillBeMember<TreeScope>> treeScopes;

    for (const auto& treeScopeEventContext : m_treeScopeEventContexts) {
        TouchEventContext* touchEventContext = treeScopeEventContext->ensureTouchEventContext();
        adjustedTouches.append(&touchEventContext->touches());
        adjustedTargetTouches.append(&touchEventContext->targetTouches());
        adjustedChangedTouches.append(&touchEventContext->changedTouches());
        treeScopes.append(&treeScopeEventContext->treeScope());
    }

    adjustTouchList(touchEvent.touches(), adjustedTouches, treeScopes);
    adjustTouchList(touchEvent.targetTouches(), adjustedTargetTouches, treeScopes);
    adjustTouchList(touchEvent.changedTouches(), adjustedChangedTouches, treeScopes);

#if ENABLE(ASSERT)
    for (const auto& treeScopeEventContext : m_treeScopeEventContexts) {
        TreeScope& treeScope = treeScopeEventContext->treeScope();
        TouchEventContext* touchEventContext = treeScopeEventContext->touchEventContext();
        checkReachability(treeScope, touchEventContext->touches());
        checkReachability(treeScope, touchEventContext->targetTouches());
        checkReachability(treeScope, touchEventContext->changedTouches());
    }
#endif
}
Exemple #4
0
void EventPath::adjustForTouchEvent(Node* node, TouchEvent& touchEvent)
{
    WillBeHeapVector<RawPtrWillBeMember<TouchList> > adjustedTouches;
    WillBeHeapVector<RawPtrWillBeMember<TouchList> > adjustedTargetTouches;
    WillBeHeapVector<RawPtrWillBeMember<TouchList> > adjustedChangedTouches;
    Vector<TreeScope*> treeScopes;

    for (size_t i = 0; i < m_treeScopeEventContexts.size(); ++i) {
        TouchEventContext* touchEventContext = m_treeScopeEventContexts[i]->ensureTouchEventContext();
        adjustedTouches.append(&touchEventContext->touches());
        adjustedTargetTouches.append(&touchEventContext->targetTouches());
        adjustedChangedTouches.append(&touchEventContext->changedTouches());
        treeScopes.append(&m_treeScopeEventContexts[i]->treeScope());
    }

    adjustTouchList(node, touchEvent.touches(), adjustedTouches, treeScopes);
    adjustTouchList(node, touchEvent.targetTouches(), adjustedTargetTouches, treeScopes);
    adjustTouchList(node, touchEvent.changedTouches(), adjustedChangedTouches, treeScopes);

#ifndef NDEBUG
    for (size_t i = 0; i < m_treeScopeEventContexts.size(); ++i) {
        TreeScope& treeScope = m_treeScopeEventContexts[i]->treeScope();
        TouchEventContext* touchEventContext = m_treeScopeEventContexts[i]->touchEventContext();
        checkReachability(treeScope, touchEventContext->touches());
        checkReachability(treeScope, touchEventContext->targetTouches());
        checkReachability(treeScope, touchEventContext->changedTouches());
    }
#endif
}
void EventListenerInfo::getEventListeners(EventTarget* target, WillBeHeapVector<EventListenerInfo>& eventInformation, bool includeAncestors)
{
    // The Node's Ancestors including self.
    WillBeHeapVector<RawPtrWillBeMember<EventTarget>> ancestors;
    ancestors.append(target);
    if (includeAncestors) {
        Node* node = target->toNode();
        for (ContainerNode* ancestor = node ? node->parentOrShadowHostNode() : nullptr; ancestor; ancestor = ancestor->parentOrShadowHostNode())
            ancestors.append(ancestor);
    }

    // Nodes and their Listeners for the concerned event types (order is top to bottom)
    for (size_t i = ancestors.size(); i; --i) {
        EventTarget* ancestor = ancestors[i - 1];
        Vector<AtomicString> eventTypes = ancestor->eventTypes();
        for (size_t j = 0; j < eventTypes.size(); ++j) {
            AtomicString& type = eventTypes[j];
            EventListenerVector* listeners = ancestor->getEventListeners(type);
            if (!listeners)
                continue;
            EventListenerVector filteredListeners;
            filteredListeners.reserveCapacity(listeners->size());
            for (size_t k = 0; k < listeners->size(); ++k) {
                if (listeners->at(k).listener->type() == EventListener::JSEventListenerType)
                    filteredListeners.append(listeners->at(k));
            }
            if (!filteredListeners.isEmpty())
                eventInformation.append(EventListenerInfo(ancestor, type, filteredListeners));
        }
    }
}
TreeScopeStyleSheetCollection::StyleResolverUpdateType TreeScopeStyleSheetCollection::compareStyleSheets(const WillBeHeapVector<RefPtrWillBeMember<CSSStyleSheet>>& oldStyleSheets, const WillBeHeapVector<RefPtrWillBeMember<CSSStyleSheet>>& newStylesheets, WillBeHeapVector<RawPtrWillBeMember<StyleSheetContents>>& addedSheets)
{
    unsigned newStyleSheetCount = newStylesheets.size();
    unsigned oldStyleSheetCount = oldStyleSheets.size();
    ASSERT(newStyleSheetCount >= oldStyleSheetCount);

    if (!newStyleSheetCount)
        return Reconstruct;

    unsigned newIndex = 0;
    for (unsigned oldIndex = 0; oldIndex < oldStyleSheetCount; ++oldIndex) {
        while (oldStyleSheets[oldIndex] != newStylesheets[newIndex]) {
            addedSheets.append(newStylesheets[newIndex]->contents());
            if (++newIndex == newStyleSheetCount)
                return Reconstruct;
        }
        if (++newIndex == newStyleSheetCount)
            return Reconstruct;
    }
    bool hasInsertions = !addedSheets.isEmpty();
    while (newIndex < newStyleSheetCount) {
        addedSheets.append(newStylesheets[newIndex]->contents());
        ++newIndex;
    }
    // If all new sheets were added at the end of the list we can just add them to existing StyleResolver.
    // If there were insertions we need to re-add all the stylesheets so rules are ordered correctly.
    return hasInsertions ? Reset : Additive;
}
PassRefPtrWillBeRawPtr<AnimatableValue> AnimatableStrokeDasharrayList::interpolateTo(const AnimatableValue* value, double fraction) const
{
    WillBeHeapVector<RefPtrWillBeMember<AnimatableValue> > from = m_values;
    WillBeHeapVector<RefPtrWillBeMember<AnimatableValue> > to = toAnimatableStrokeDasharrayList(value)->m_values;

    // The spec states that if the sum of all values is zero, this should be
    // treated like a value of 'none', which means that a solid line is drawn.
    // Since we animate to and from values of zero, treat a value of 'none' the
    // same. If both the two and from values are 'none', we return 'none'
    // rather than '0 0'.
    if (from.isEmpty() && to.isEmpty())
        return takeConstRef(this);
    if (from.isEmpty() || to.isEmpty()) {
        DEFINE_STATIC_REF_WILL_BE_PERSISTENT(AnimatableSVGLength, zeroPixels, (AnimatableSVGLength::create(SVGLength::create())));
        if (from.isEmpty()) {
            from.append(zeroPixels);
            from.append(zeroPixels);
        }
        if (to.isEmpty()) {
            to.append(zeroPixels);
            to.append(zeroPixels);
        }
    }

    WillBeHeapVector<RefPtrWillBeMember<AnimatableValue> > interpolatedValues;
    bool success = interpolateLists(from, to, fraction, interpolatedValues);
    ASSERT_UNUSED(success, success);
    return adoptRefWillBeNoop(new AnimatableStrokeDasharrayList(interpolatedValues));
}
void SimplifyMarkupCommand::doApply()
{
    ContainerNode* rootNode = m_firstNode->parentNode();
    WillBeHeapVector<RefPtrWillBeMember<ContainerNode>> nodesToRemove;

    // Walk through the inserted nodes, to see if there are elements that could be removed
    // without affecting the style. The goal is to produce leaner markup even when starting
    // from a verbose fragment.
    // We look at inline elements as well as non top level divs that don't have attributes.
    for (Node* node = m_firstNode.get(); node && node != m_nodeAfterLast; node = NodeTraversal::next(*node)) {
        if (node->hasChildren() || (node->isTextNode() && node->nextSibling()))
            continue;

        ContainerNode* startingNode = node->parentNode();
        if (!startingNode)
            continue;
        RenderStyle* startingStyle = startingNode->renderStyle();
        if (!startingStyle)
            continue;
        ContainerNode* currentNode = startingNode;
        ContainerNode* topNodeWithStartingStyle = nullptr;
        while (currentNode != rootNode) {
            if (currentNode->parentNode() != rootNode && isRemovableBlock(currentNode))
                nodesToRemove.append(currentNode);

            currentNode = currentNode->parentNode();
            if (!currentNode)
                break;

            if (!currentNode->renderer() || !currentNode->renderer()->isRenderInline() || toRenderInline(currentNode->renderer())->alwaysCreateLineBoxes())
                continue;

            if (currentNode->firstChild() != currentNode->lastChild()) {
                topNodeWithStartingStyle = 0;
                break;
            }

            if (!currentNode->renderStyle()->visualInvalidationDiff(*startingStyle).hasDifference())
                topNodeWithStartingStyle = currentNode;

        }
        if (topNodeWithStartingStyle) {
            for (ContainerNode* node = startingNode; node != topNodeWithStartingStyle; node = node->parentNode())
                nodesToRemove.append(node);
        }
    }

    // we perform all the DOM mutations at once.
    for (size_t i = 0; i < nodesToRemove.size(); ++i) {
        // FIXME: We can do better by directly moving children from nodesToRemove[i].
        int numPrunedAncestors = pruneSubsequentAncestorsToRemove(nodesToRemove, i);
        if (numPrunedAncestors < 0)
            continue;
        removeNodePreservingChildren(nodesToRemove[i], AssumeContentIsAlwaysEditable);
        i += numPrunedAncestors;
    }
}
void HTMLImport::recalcTreeState(HTMLImport* root)
{
    WillBeHeapHashMap<RawPtrWillBeMember<HTMLImport>, HTMLImportState> snapshot;
    WillBeHeapVector<RawPtrWillBeMember<HTMLImport>> updated;

    for (HTMLImport* i = root; i; i = traverseNext(i)) {
        snapshot.add(i, i->state());
        i->m_state = HTMLImportState::invalidState();
    }

    // The post-visit DFS order matters here because
    // HTMLImportStateResolver in recalcState() Depends on
    // |m_state| of its children and precedents of ancestors.
    // Accidental cycle dependency of state computation is prevented
    // by invalidateCachedState() and isStateCacheValid() check.
    for (HTMLImport* i = traverseFirstPostOrder(root); i; i = traverseNextPostOrder(i)) {
        ASSERT(!i->m_state.isValid());
        i->m_state = HTMLImportStateResolver(i).resolve();

        HTMLImportState newState = i->state();
        HTMLImportState oldState = snapshot.get(i);
        // Once the state reaches Ready, it shouldn't go back.
        ASSERT(!oldState.isReady() || oldState <= newState);
        if (newState != oldState)
            updated.append(i);
    }

    for (size_t i = 0; i < updated.size(); ++i)
        updated[i]->stateDidChange();
}
void CSSSegmentedFontFace::match(const String& text, WillBeHeapVector<RefPtrWillBeMember<FontFace> >& faces) const
{
    for (FontFaceList::const_iterator it = m_fontFaces.begin(); it != m_fontFaces.end(); ++it) {
        if ((*it)->cssFontFace()->ranges().intersectsWith(text))
            faces.append(*it);
    }
}
void AnimationTimeline::serviceAnimations(TimingUpdateReason reason)
{
    TRACE_EVENT0("blink", "AnimationTimeline::serviceAnimations");

    m_lastCurrentTimeInternal = currentTimeInternal();

    m_timing->cancelWake();

    WillBeHeapVector<RawPtrWillBeMember<Animation>> animations;
    animations.reserveInitialCapacity(m_animationsNeedingUpdate.size());
    for (RefPtrWillBeMember<Animation> animation : m_animationsNeedingUpdate)
        animations.append(animation.get());

    std::sort(animations.begin(), animations.end(), Animation::hasLowerPriority);

    for (Animation* animation : animations) {
        if (!animation->update(reason))
            m_animationsNeedingUpdate.remove(animation);
    }

    ASSERT(m_outdatedAnimationCount == 0);

#if ENABLE(ASSERT)
    for (const auto& animation : m_animationsNeedingUpdate)
        ASSERT(!animation->outdated());
#endif
}
Exemple #12
0
SmartClipData SmartClip::dataForRect(const IntRect& cropRect)
{
    IntRect resizedCropRect = applyScaleWithoutCollapsingToZero(cropRect, 1 / pageScaleFactor());

    Node* bestNode = findBestOverlappingNode(m_frame->document(), resizedCropRect);
    if (!bestNode)
        return SmartClipData();

    if (Node* nodeFromFrame = nodeInsideFrame(bestNode)) {
        // FIXME: This code only hit-tests a single iframe. It seems like we ought support nested frames.
        if (Node* bestNodeInFrame = findBestOverlappingNode(nodeFromFrame, resizedCropRect))
            bestNode = bestNodeInFrame;
    }

    WillBeHeapVector<RawPtrWillBeMember<Node> > hitNodes;
    collectOverlappingChildNodes(bestNode, resizedCropRect, hitNodes);

    if (hitNodes.isEmpty() || hitNodes.size() == bestNode->countChildren()) {
        hitNodes.clear();
        hitNodes.append(bestNode);
    }

    // Unite won't work with the empty rect, so we initialize to the first rect.
    IntRect unitedRects = hitNodes[0]->pixelSnappedBoundingBox();
    StringBuilder collectedText;
    for (size_t i = 0; i < hitNodes.size(); ++i) {
        collectedText.append(extractTextFromNode(hitNodes[i]));
        unitedRects.unite(hitNodes[i]->pixelSnappedBoundingBox());
    }

    return SmartClipData(bestNode, convertRectToWindow(unitedRects), collectedText.toString());
}
void AnimationTimeline::serviceAnimations(TimingUpdateReason reason)
{
    TRACE_EVENT0("webkit", "AnimationTimeline::serviceAnimations");

    m_timing->cancelWake();

    double timeToNextEffect = std::numeric_limits<double>::infinity();
    WillBeHeapVector<RawPtrWillBeMember<AnimationPlayer> > players;
    for (WillBeHeapHashSet<RefPtrWillBeMember<AnimationPlayer> >::iterator it = m_playersNeedingUpdate.begin(); it != m_playersNeedingUpdate.end(); ++it)
        players.append(it->get());

    std::sort(players.begin(), players.end(), AnimationPlayer::hasLowerPriority);

    for (size_t i = 0; i < players.size(); ++i) {
        AnimationPlayer* player = players[i];
        if (player->update(reason))
            timeToNextEffect = std::min(timeToNextEffect, player->timeToEffectChange());
        else
            m_playersNeedingUpdate.remove(player);
    }

    if (timeToNextEffect < s_minimumDelay)
        m_timing->serviceOnNextFrame();
    else if (timeToNextEffect != std::numeric_limits<double>::infinity())
        m_timing->wakeAfter(timeToNextEffect - s_minimumDelay);

    ASSERT(!hasOutdatedAnimationPlayer());
}
Exemple #14
0
void PageAnimator::serviceScriptedAnimations(double monotonicAnimationStartTime)
{
    m_animationFramePending = false;
    TemporaryChange<bool> servicing(m_servicingAnimations, true);

    WillBeHeapVector<RefPtrWillBeMember<Document> > documents;
    for (RefPtr<Frame> frame = m_page->mainFrame(); frame; frame = frame->tree().traverseNext()) {
        if (frame->isLocalFrame())
            documents.append(toLocalFrame(frame.get())->document());
    }

    for (size_t i = 0; i < documents.size(); ++i) {
        if (documents[i]->frame()) {
            documents[i]->view()->serviceScrollAnimations();

            if (const FrameView::ScrollableAreaSet* scrollableAreas = documents[i]->view()->scrollableAreas()) {
                for (FrameView::ScrollableAreaSet::iterator it = scrollableAreas->begin(); it != scrollableAreas->end(); ++it)
                    (*it)->serviceScrollAnimations();
            }
        }
    }

    for (size_t i = 0; i < documents.size(); ++i) {
        DocumentAnimations::updateAnimationTimingForAnimationFrame(*documents[i], monotonicAnimationStartTime);
        SVGDocumentExtensions::serviceOnAnimationFrame(*documents[i], monotonicAnimationStartTime);
    }

    for (size_t i = 0; i < documents.size(); ++i)
        documents[i]->serviceScriptedAnimations(monotonicAnimationStartTime);
}
Exemple #15
0
void CSSAnimations::calculateTransitionActiveInterpolations(CSSAnimationUpdate* update, const Element* animatingElement, double timelineCurrentTime)
{
    ActiveAnimations* activeAnimations = animatingElement ? animatingElement->activeAnimations() : nullptr;
    AnimationStack* animationStack = activeAnimations ? &activeAnimations->defaultStack() : nullptr;

    WillBeHeapHashMap<CSSPropertyID, RefPtrWillBeMember<Interpolation>> activeInterpolationsForTransitions;
    if (update->newTransitions().isEmpty() && update->cancelledTransitions().isEmpty()) {
        activeInterpolationsForTransitions = AnimationStack::activeInterpolations(animationStack, 0, 0, Animation::TransitionPriority, timelineCurrentTime);
    } else {
        WillBeHeapVector<RawPtrWillBeMember<InertAnimation>> newTransitions;
        for (const auto& entry : update->newTransitions())
            newTransitions.append(entry.value.animation.get());

        WillBeHeapHashSet<RawPtrWillBeMember<const AnimationPlayer>> cancelledAnimationPlayers;
        if (!update->cancelledTransitions().isEmpty()) {
            ASSERT(activeAnimations);
            const TransitionMap& transitionMap = activeAnimations->cssAnimations().m_transitions;
            for (CSSPropertyID id : update->cancelledTransitions()) {
                ASSERT(transitionMap.contains(id));
                cancelledAnimationPlayers.add(transitionMap.get(id).player.get());
            }
        }

        activeInterpolationsForTransitions = AnimationStack::activeInterpolations(animationStack, &newTransitions, &cancelledAnimationPlayers, Animation::TransitionPriority, timelineCurrentTime);
    }

    // Properties being animated by animations don't get values from transitions applied.
    if (!update->activeInterpolationsForAnimations().isEmpty() && !activeInterpolationsForTransitions.isEmpty()) {
        for (const auto& entry : update->activeInterpolationsForAnimations())
            activeInterpolationsForTransitions.remove(entry.key);
    }
    update->adoptActiveInterpolationsForTransitions(activeInterpolationsForTransitions);
}
void ScreenOrientationController::notifyOrientationChanged()
{
    ASSERT(RuntimeEnabledFeatures::screenOrientationEnabled());

    if (!isActiveAndVisible())
        return;

    updateOrientation();

    // Keep track of the frames that need to be notified before notifying the
    // current frame as it will prevent side effects from the change event
    // handlers.
    WillBeHeapVector<RefPtrWillBeMember<LocalFrame> > childFrames;
    for (Frame* child = frame()->tree().firstChild(); child; child = child->tree().nextSibling()) {
        if (child->isLocalFrame())
            childFrames.append(toLocalFrame(child));
    }

    // Notify current orientation object.
    if (!m_dispatchEventTimer.isActive())
        m_dispatchEventTimer.startOneShot(0, FROM_HERE);

    // ... and child frames, if they have a ScreenOrientationController.
    for (size_t i = 0; i < childFrames.size(); ++i) {
        if (ScreenOrientationController* controller = ScreenOrientationController::from(*childFrames[i]))
            controller->notifyOrientationChanged();
    }
}
void CSSSegmentedFontFace::match(const String& text, WillBeHeapVector<RefPtrWillBeMember<FontFace> >& faces) const
{
    for (const auto& fontFace : m_fontFaces) {
        if (fontFace->cssFontFace()->ranges().intersectsWith(text))
            faces.append(fontFace);
    }
}
void HTMLFormattingElementList::tryToEnsureNoahsArkConditionQuickly(HTMLStackItem* newItem, WillBeHeapVector<RawPtrWillBeMember<HTMLStackItem> >& remainingCandidates)
{
    ASSERT(remainingCandidates.isEmpty());

    if (m_entries.size() < kNoahsArkCapacity)
        return;

    // Use a vector with inline capacity to avoid a malloc in the common case
    // of a quickly ensuring the condition.
    WillBeHeapVector<RawPtrWillBeMember<HTMLStackItem>, 10> candidates;

    size_t newItemAttributeCount = newItem->attributes().size();

    for (size_t i = m_entries.size(); i; ) {
        --i;
        Entry& entry = m_entries[i];
        if (entry.isMarker())
            break;

        // Quickly reject obviously non-matching candidates.
        HTMLStackItem* candidate = entry.stackItem().get();
        if (newItem->localName() != candidate->localName() || newItem->namespaceURI() != candidate->namespaceURI())
            continue;
        if (candidate->attributes().size() != newItemAttributeCount)
            continue;

        candidates.append(candidate);
    }

    if (candidates.size() < kNoahsArkCapacity)
        return; // There's room for the new element in the ark. There's no need to copy out the remainingCandidates.

    remainingCandidates.appendVector(candidates);
}
FontFaceSetIterable::IterationSource* FontFaceSet::startIteration(ScriptState*, ExceptionState&)
{
    // Setlike should iterate each item in insertion order, and items should
    // be keep on up to date. But since blink does not have a way to hook up CSS
    // modification, take a snapshot here, and make it ordered as follows.
    WillBeHeapVector<RefPtrWillBeMember<FontFace>> fontFaces;
    if (inActiveDocumentContext()) {
        const WillBeHeapListHashSet<RefPtrWillBeMember<FontFace>>& cssConnectedFaces = cssConnectedFontFaceList();
        fontFaces.reserveInitialCapacity(cssConnectedFaces.size() + m_nonCSSConnectedFaces.size());
        for (const auto& fontFace : cssConnectedFaces)
            fontFaces.append(fontFace);
        for (const auto& fontFace : m_nonCSSConnectedFaces)
            fontFaces.append(fontFace);
    }
    return new IterationSource(fontFaces);
}
bool MHTMLParser::parseArchiveWithHeader(MIMEHeader* header, WillBeHeapVector<RefPtrWillBeMember<ArchiveResource>>& resources)
{
    if (!header) {
        WTF_LOG_ERROR("Failed to parse MHTML part: no header.");
        return false;
    }

    if (!header->isMultipart()) {
        // With IE a page with no resource is not multi-part.
        bool endOfArchiveReached = false;
        RefPtrWillBeRawPtr<ArchiveResource> resource = parseNextPart(*header, String(), String(), endOfArchiveReached);
        if (!resource)
            return false;
        resources.append(resource);
        return true;
    }

    // Skip the message content (it's a generic browser specific message).
    skipLinesUntilBoundaryFound(m_lineReader, header->endOfPartBoundary());

    bool endOfArchive = false;
    while (!endOfArchive) {
        RefPtrWillBeRawPtr<MIMEHeader> resourceHeader = MIMEHeader::parseHeader(&m_lineReader);
        if (!resourceHeader) {
            WTF_LOG_ERROR("Failed to parse MHTML, invalid MIME header.");
            return false;
        }
        if (resourceHeader->contentType() == "multipart/alternative") {
            // Ignore IE nesting which makes little sense (IE seems to nest only some of the frames).
            if (!parseArchiveWithHeader(resourceHeader.get(), resources)) {
                WTF_LOG_ERROR("Failed to parse MHTML subframe.");
                return false;
            }
            bool endOfPartReached = skipLinesUntilBoundaryFound(m_lineReader, header->endOfPartBoundary());
            ASSERT_UNUSED(endOfPartReached, endOfPartReached);
            continue;
        }

        RefPtrWillBeRawPtr<ArchiveResource> resource = parseNextPart(*resourceHeader, header->endOfPartBoundary(), header->endOfDocumentBoundary(), endOfArchive);
        if (!resource) {
            WTF_LOG_ERROR("Failed to parse MHTML part.");
            return false;
        }
        resources.append(resource);
    }
    return true;
}
void findGoodTouchTargets(const IntRect& touchBox, LocalFrame* mainFrame, Vector<IntRect>& goodTargets, WillBeHeapVector<RawPtrWillBeMember<Node> >& highlightNodes)
{
    goodTargets.clear();

    int touchPointPadding = ceil(std::max(touchBox.width(), touchBox.height()) * 0.5);

    IntPoint touchPoint = touchBox.center();
    IntPoint contentsPoint = mainFrame->view()->windowToContents(touchPoint);

    HitTestResult result = mainFrame->eventHandler().hitTestResultAtPoint(contentsPoint, HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::ConfusingAndOftenMisusedDisallowShadowContent, IntSize(touchPointPadding, touchPointPadding));
    const WillBeHeapListHashSet<RefPtrWillBeMember<Node> >& hitResults = result.rectBasedTestResult();

    // Blacklist nodes that are container of disambiguated nodes.
    // It is not uncommon to have a clickable <div> that contains other clickable objects.
    // This heuristic avoids excessive disambiguation in that case.
    WillBeHeapHashSet<RawPtrWillBeMember<Node> > blackList;
    for (WillBeHeapListHashSet<RefPtrWillBeMember<Node> >::const_iterator it = hitResults.begin(); it != hitResults.end(); ++it) {
        // Ignore any Nodes that can't be clicked on.
        RenderObject* renderer = it->get()->renderer();
        if (!renderer || !it->get()->willRespondToMouseClickEvents())
            continue;

        // Blacklist all of the Node's containers.
        for (RenderBlock* container = renderer->containingBlock(); container; container = container->containingBlock()) {
            Node* containerNode = container->node();
            if (!containerNode)
                continue;
            if (!blackList.add(containerNode).isNewEntry)
                break;
        }
    }

    WillBeHeapHashMap<RawPtrWillBeMember<Node>, TouchTargetData> touchTargets;
    float bestScore = 0;
    for (WillBeHeapListHashSet<RefPtrWillBeMember<Node> >::const_iterator it = hitResults.begin(); it != hitResults.end(); ++it) {
        for (Node* node = it->get(); node; node = node->parentNode()) {
            if (blackList.contains(node))
                continue;
            if (node->isDocumentNode() || isHTMLHtmlElement(*node) || isHTMLBodyElement(*node))
                break;
            if (node->willRespondToMouseClickEvents()) {
                TouchTargetData& targetData = touchTargets.add(node, TouchTargetData()).storedValue->value;
                targetData.windowBoundingBox = boundingBoxForEventNodes(node);
                targetData.score = scoreTouchTarget(touchPoint, touchPointPadding, targetData.windowBoundingBox);
                bestScore = std::max(bestScore, targetData.score);
                break;
            }
        }
    }

    for (WillBeHeapHashMap<RawPtrWillBeMember<Node>, TouchTargetData>::iterator it = touchTargets.begin(); it != touchTargets.end(); ++it) {
        // Currently the scoring function uses the overlap area with the fat point as the score.
        // We ignore the candidates that has less than 1/2 overlap (we consider not really ambiguous enough) than the best candidate to avoid excessive popups.
        if (it->value.score < bestScore * 0.5)
            continue;
        goodTargets.append(it->value.windowBoundingBox);
        highlightNodes.append(it->key);
    }
}
Exemple #22
0
PassRefPtrWillBeRawPtr<NodeList> TreeScopeEventContext::ensureEventPath(EventPath& path)
{
    if (m_eventPath)
        return m_eventPath;

    WillBeHeapVector<RefPtrWillBeMember<Node> > nodes;
    nodes.reserveInitialCapacity(path.size());
    for (size_t i = 0; i < path.size(); ++i) {
        TreeScope& treeScope = path[i].treeScopeEventContext().treeScope();
        if (treeScope.rootNode().isShadowRoot() && toShadowRoot(treeScope).type() == ShadowRoot::AuthorShadowRoot)
            nodes.append(path[i].node());
        else if (path[i].treeScopeEventContext().isInclusiveAncestorOf(*this))
            nodes.append(path[i].node());
    }
    m_eventPath = StaticNodeList::adopt(nodes);
    return m_eventPath;
}
void HTMLFormElement::collectImageElements(Node& root, WillBeHeapVector<RawPtrWillBeMember<HTMLImageElement>>& elements)
{
    elements.clear();
    for (HTMLImageElement& image : Traversal<HTMLImageElement>::startsAfter(root)) {
        if (image.formOwner() == this)
            elements.append(&image);
    }
}
void HTMLCollection::namedItems(const AtomicString& name, WillBeHeapVector<RefPtrWillBeMember<Element>>& result) const
{
    ASSERT(result.isEmpty());
    if (name.isEmpty())
        return;

    updateIdNameCache();

    const NamedItemCache& cache = namedItemCache();
    if (WillBeHeapVector<RawPtrWillBeMember<Element>>* idResults = cache.getElementsById(name)) {
        for (unsigned i = 0; i < idResults->size(); ++i)
            result.append(idResults->at(i));
    }
    if (WillBeHeapVector<RawPtrWillBeMember<Element>>* nameResults = cache.getElementsByName(name)) {
        for (unsigned i = 0; i < nameResults->size(); ++i)
            result.append(nameResults->at(i));
    }
}
 void executeScriptInIsolatedWorld(const String& script) const
 {
     v8::HandleScope scope(v8::Isolate::GetCurrent());
     WillBeHeapVector<ScriptSourceCode> sources;
     sources.append(ScriptSourceCode(script));
     Vector<v8::Local<v8::Value>> results;
     m_scriptController->executeScriptInIsolatedWorld(isolatedWorldId, sources, extensionGroup, 0);
     pumpPendingRequestsDoNotUse(m_webViewHelper.webViewImpl()->mainFrame());
 }
WillBeHeapVector<RefPtrWillBeMember<Animation>> AnimationTimeline::getAnimations()
{
    WillBeHeapVector<RefPtrWillBeMember<Animation>> animations;
    for (const auto& animation : m_animations) {
        if (animation->effect() && (animation->effect()->isCurrent() || animation->effect()->isInEffect()))
            animations.append(animation);
    }
    std::sort(animations.begin(), animations.end(), compareAnimations);
    return animations;
}
WillBeHeapVector<RawPtrWillBeMember<Element>> TreeScope::elementsFromPoint(int x, int y) const
{
    WillBeHeapVector<RawPtrWillBeMember<Element>> elements;

    Document& document = rootNode().document();
    IntPoint hitPoint(x, y);
    if (!pointWithScrollAndZoomIfPossible(document, hitPoint))
        return elements;

    HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::ListBased | HitTestRequest::PenetratingList);
    HitTestResult result(request, hitPoint);
    document.layoutView()->hitTest(result);

    Node* lastNode = nullptr;
    for (const auto rectBasedNode : result.listBasedTestResult()) {
        Node* node = rectBasedNode.get();
        if (!node || !node->isElementNode() || node->isDocumentNode())
            continue;

        if (node->isPseudoElement() || node->isTextNode())
            node = node->parentOrShadowHostNode();
        node = ancestorInThisScope(node);

        // Prune duplicate entries. A pseduo ::before content above its parent
        // node should only result in a single entry.
        if (node == lastNode)
            continue;

        if (node && node->isElementNode()) {
            elements.append(toElement(node));
            lastNode = node;
        }
    }

    if (rootNode().isDocumentNode()) {
        if (Element* rootElement = toDocument(rootNode()).documentElement()) {
            if (elements.isEmpty() || elements.last() != rootElement)
                elements.append(rootElement);
        }
    }

    return elements;
}
inline void DistributionPool::populateChildren(const ContainerNode& parent)
{
    clear();
    for (Node* child = parent.firstChild(); child; child = child->nextSibling()) {
        if (isHTMLSlotElement(child)) {
            // TODO(hayato): Support re-distribution across v0 and v1 shadow trees
            continue;
        }
        if (isActiveInsertionPoint(*child)) {
            InsertionPoint* insertionPoint = toInsertionPoint(child);
            for (size_t i = 0; i < insertionPoint->distributedNodesSize(); ++i)
                m_nodes.append(insertionPoint->distributedNodeAt(i));
        } else {
            m_nodes.append(child);
        }
    }
    m_distributed.resize(m_nodes.size());
    m_distributed.fill(false);
}
Exemple #29
0
WillBeHeapVector<RefPtrWillBeMember<AnimationPlayer>> AnimationTimeline::getAnimationPlayers()
{
    WillBeHeapVector<RefPtrWillBeMember<AnimationPlayer>> animationPlayers;
    for (const auto& player : m_players) {
        if (player->source() && (player->source()->isCurrent() || player->source()->isInEffect()))
            animationPlayers.append(player);
    }
    std::sort(animationPlayers.begin(), animationPlayers.end(), compareAnimationPlayers);
    return animationPlayers;
}
void SlotAssignment::resolveAssignment(const ShadowRoot& shadowRoot)
{
    m_assignment.clear();

    using Name2Slot = WillBeHeapHashMap<AtomicString, RefPtrWillBeMember<HTMLSlotElement>>;
    Name2Slot name2slot;
    HTMLSlotElement* defaultSlot = nullptr;
    WillBeHeapVector<RefPtrWillBeMember<HTMLSlotElement>> slots;

    // TODO(hayato): Cache slots elements so that we do not have to travese the shadow tree. See ShadowRoot::descendantInsertionPoints()
    for (HTMLSlotElement& slot : Traversal<HTMLSlotElement>::descendantsOf(shadowRoot)) {
        slot.clearDistribution();

        slots.append(&slot);

        AtomicString name = slot.fastGetAttribute(HTMLNames::nameAttr);
        if (name.isNull() || name.isEmpty()) {
            if (!defaultSlot)
                defaultSlot = &slot;
        } else {
            name2slot.add(name, &slot);
        }
    }

    for (Node& child : NodeTraversal::childrenOf(*shadowRoot.host())) {
        if (child.isElementNode()) {
            if (isActiveInsertionPoint(child)) {
                // TODO(hayato): Support re-distribution across v0 and v1 shadow trees
                detachNotAssignedNode(child);
                continue;
            }
            AtomicString slotName = toElement(child).fastGetAttribute(HTMLNames::slotAttr);
            if (slotName.isNull() || slotName.isEmpty()) {
                if (defaultSlot)
                    assign(child, *defaultSlot);
                else
                    detachNotAssignedNode(child);
            } else {
                HTMLSlotElement* slot = name2slot.get(slotName);
                if (slot)
                    assign(child, *slot);
                else
                    detachNotAssignedNode(child);
            }
        } else if (defaultSlot) {
            assign(child, *defaultSlot);
        } else {
            detachNotAssignedNode(child);
        }
    }

    // Update each slot's distribution in reverse tree order so that a child slot is visited before its parent slot.
    for (auto slot = slots.rbegin(); slot != slots.rend(); ++slot)
        (*slot)->updateDistributedNodesWithFallback();
}