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 }
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 }
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()); }
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); }
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); } }
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); }
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(); }