bool InspectorOverlay::handleMouseMove(const PlatformMouseEvent& event) { if (!shouldSearchForNode()) return false; LocalFrame* frame = m_frameImpl->frame(); if (!frame || !frame->view() || frame->contentLayoutItem().isNull()) return false; Node* node = hoveredNodeForEvent(frame, event, event.shiftKey()); // Do not highlight within user agent shadow root unless requested. if (m_inspectMode != InspectorDOMAgent::SearchingForUAShadow) { ShadowRoot* shadowRoot = InspectorDOMAgent::userAgentShadowRoot(node); if (shadowRoot) node = &shadowRoot->host(); } // Shadow roots don't have boxes - use host element instead. if (node && node->isShadowRoot()) node = node->parentOrShadowHostNode(); if (!node) return true; Node* eventTarget = event.shiftKey() ? hoveredNodeForEvent(frame, event, false) : nullptr; if (eventTarget == node) eventTarget = nullptr; if (node && m_inspectModeHighlightConfig) { m_hoveredNodeForInspectMode = node; if (m_domAgent) m_domAgent->nodeHighlightedInOverlay(node); highlightNode(node, eventTarget, *m_inspectModeHighlightConfig, event.ctrlKey() || event.metaKey()); } return true; }
static void frameContentAsPlainText(size_t maxChars, LocalFrame* frame, StringBuilder& output) { Document* document = frame->document(); if (!document) return; if (!frame->view() || frame->view()->shouldThrottleRendering()) return; DCHECK(!frame->view()->needsLayout()); DCHECK(!document->needsLayoutTreeUpdate()); // Select the document body. if (document->body()) { const EphemeralRange range = EphemeralRange::rangeOfContents(*document->body()); // The text iterator will walk nodes giving us text. This is similar to // the plainText() function in core/editing/TextIterator.h, but we // implement the maximum size and also copy the results directly into a // wstring, avoiding the string conversion. for (TextIterator it(range.startPosition(), range.endPosition()); !it.atEnd(); it.advance()) { it.text().appendTextToStringBuilder(output, 0, maxChars - output.length()); if (output.length() >= maxChars) return; // Filled up the buffer. } } // The separator between frames when the frames are converted to plain text. const LChar frameSeparator[] = {'\n', '\n'}; const size_t frameSeparatorLength = WTF_ARRAY_LENGTH(frameSeparator); // Recursively walk the children. const FrameTree& frameTree = frame->tree(); for (Frame* curChild = frameTree.firstChild(); curChild; curChild = curChild->tree().nextSibling()) { if (!curChild->isLocalFrame()) continue; LocalFrame* curLocalChild = toLocalFrame(curChild); // Ignore the text of non-visible frames. LayoutViewItem contentLayoutItem = curLocalChild->contentLayoutItem(); LayoutPart* ownerLayoutObject = curLocalChild->ownerLayoutObject(); if (contentLayoutItem.isNull() || !contentLayoutItem.size().width() || !contentLayoutItem.size().height() || (contentLayoutItem.location().x() + contentLayoutItem.size().width() <= 0) || (contentLayoutItem.location().y() + contentLayoutItem.size().height() <= 0) || (ownerLayoutObject && ownerLayoutObject->style() && ownerLayoutObject->style()->visibility() != EVisibility::Visible)) { continue; } // Make sure the frame separator won't fill up the buffer, and give up if // it will. The danger is if the separator will make the buffer longer than // maxChars. This will cause the computation above: // maxChars - output->size() // to be a negative number which will crash when the subframe is added. if (output.length() >= maxChars - frameSeparatorLength) return; output.append(frameSeparator, frameSeparatorLength); frameContentAsPlainText(maxChars, curLocalChild, output); if (output.length() >= maxChars) return; // Filled up the buffer. } }