| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (C) 2013 Google Inc. All rights reserved. | 2 * Copyright (C) 2013 Google Inc. All rights reserved. |
| 3 * | 3 * |
| 4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
| 5 * modification, are permitted provided that the following conditions are | 5 * modification, are permitted provided that the following conditions are |
| 6 * met: | 6 * met: |
| 7 * | 7 * |
| 8 * * Redistributions of source code must retain the above copyright | 8 * * Redistributions of source code must retain the above copyright |
| 9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
| 10 * * Redistributions in binary form must reproduce the above | 10 * * Redistributions in binary form must reproduce the above |
| (...skipping 25 matching lines...) Expand all Loading... |
| 36 #include "core/dom/NodeTraversal.h" | 36 #include "core/dom/NodeTraversal.h" |
| 37 #include "core/frame/LocalDOMWindow.h" | 37 #include "core/frame/LocalDOMWindow.h" |
| 38 #include "core/frame/FrameView.h" | 38 #include "core/frame/FrameView.h" |
| 39 #include "core/html/HTMLFrameOwnerElement.h" | 39 #include "core/html/HTMLFrameOwnerElement.h" |
| 40 #include "core/layout/LayoutObject.h" | 40 #include "core/layout/LayoutObject.h" |
| 41 #include "core/page/Page.h" | 41 #include "core/page/Page.h" |
| 42 #include "wtf/text/StringBuilder.h" | 42 #include "wtf/text/StringBuilder.h" |
| 43 | 43 |
| 44 namespace blink { | 44 namespace blink { |
| 45 | 45 |
| 46 static IntRect applyScaleWithoutCollapsingToZero(const IntRect& rect, float scal
e) | 46 static IntRect convertToContentCoordinatesWithoutCollapsingToZero(const IntRect&
rectInViewport, const FrameView* view) |
| 47 { | 47 { |
| 48 IntRect result = rect; | 48 IntRect rectInContents = view->viewportToContents(rectInViewport); |
| 49 result.scale(scale); | 49 if (rectInViewport.width() > 0 && !rectInContents.width()) |
| 50 if (rect.width() > 0 && !result.width()) | 50 rectInContents.setWidth(1); |
| 51 result.setWidth(1); | 51 if (rectInViewport.height() > 0 && !rectInContents.height()) |
| 52 if (rect.height() > 0 && !result.height()) | 52 rectInContents.setHeight(1); |
| 53 result.setHeight(1); | 53 return rectInContents; |
| 54 return result; | |
| 55 } | 54 } |
| 56 | 55 |
| 57 static Node* nodeInsideFrame(Node* node) | 56 static Node* nodeInsideFrame(Node* node) |
| 58 { | 57 { |
| 59 if (node->isFrameOwnerElement()) | 58 if (node->isFrameOwnerElement()) |
| 60 return toHTMLFrameOwnerElement(node)->contentDocument(); | 59 return toHTMLFrameOwnerElement(node)->contentDocument(); |
| 61 return nullptr; | 60 return nullptr; |
| 62 } | 61 } |
| 63 | 62 |
| 64 IntRect SmartClipData::rect() const | 63 IntRect SmartClipData::rectInViewport() const |
| 65 { | 64 { |
| 66 return m_rect; | 65 return m_rectInViewport; |
| 67 } | 66 } |
| 68 | 67 |
| 69 const String& SmartClipData::clipData() const | 68 const String& SmartClipData::clipData() const |
| 70 { | 69 { |
| 71 return m_string; | 70 return m_string; |
| 72 } | 71 } |
| 73 | 72 |
| 74 SmartClip::SmartClip(PassRefPtrWillBeRawPtr<LocalFrame> frame) | 73 SmartClip::SmartClip(PassRefPtrWillBeRawPtr<LocalFrame> frame) |
| 75 : m_frame(frame) | 74 : m_frame(frame) |
| 76 { | 75 { |
| 77 } | 76 } |
| 78 | 77 |
| 79 SmartClipData SmartClip::dataForRect(const IntRect& cropRect) | 78 SmartClipData SmartClip::dataForRect(const IntRect& cropRectInViewport) |
| 80 { | 79 { |
| 81 IntRect resizedCropRect = applyScaleWithoutCollapsingToZero(cropRect, 1 / pa
geScaleFactor()); | 80 Node* bestNode = findBestOverlappingNode(m_frame->document(), cropRectInView
port); |
| 82 | |
| 83 Node* bestNode = findBestOverlappingNode(m_frame->document(), resizedCropRec
t); | |
| 84 if (!bestNode) | 81 if (!bestNode) |
| 85 return SmartClipData(); | 82 return SmartClipData(); |
| 86 | 83 |
| 87 if (Node* nodeFromFrame = nodeInsideFrame(bestNode)) { | 84 if (Node* nodeFromFrame = nodeInsideFrame(bestNode)) { |
| 88 // FIXME: This code only hit-tests a single iframe. It seems like we oug
ht support nested frames. | 85 // FIXME: This code only hit-tests a single iframe. It seems like we oug
ht support nested frames. |
| 89 if (Node* bestNodeInFrame = findBestOverlappingNode(nodeFromFrame, resiz
edCropRect)) | 86 if (Node* bestNodeInFrame = findBestOverlappingNode(nodeFromFrame, cropR
ectInViewport)) |
| 90 bestNode = bestNodeInFrame; | 87 bestNode = bestNodeInFrame; |
| 91 } | 88 } |
| 92 | 89 |
| 93 WillBeHeapVector<RawPtrWillBeMember<Node>> hitNodes; | 90 WillBeHeapVector<RawPtrWillBeMember<Node>> hitNodes; |
| 94 collectOverlappingChildNodes(bestNode, resizedCropRect, hitNodes); | 91 collectOverlappingChildNodes(bestNode, cropRectInViewport, hitNodes); |
| 95 | 92 |
| 96 if (hitNodes.isEmpty() || hitNodes.size() == bestNode->countChildren()) { | 93 if (hitNodes.isEmpty() || hitNodes.size() == bestNode->countChildren()) { |
| 97 hitNodes.clear(); | 94 hitNodes.clear(); |
| 98 hitNodes.append(bestNode); | 95 hitNodes.append(bestNode); |
| 99 } | 96 } |
| 100 | 97 |
| 101 // Unite won't work with the empty rect, so we initialize to the first rect. | 98 // Unite won't work with the empty rect, so we initialize to the first rect. |
| 102 IntRect unitedRects = hitNodes[0]->pixelSnappedBoundingBox(); | 99 IntRect unitedRects = hitNodes[0]->pixelSnappedBoundingBox(); |
| 103 StringBuilder collectedText; | 100 StringBuilder collectedText; |
| 104 for (size_t i = 0; i < hitNodes.size(); ++i) { | 101 for (size_t i = 0; i < hitNodes.size(); ++i) { |
| 105 collectedText.append(extractTextFromNode(hitNodes[i])); | 102 collectedText.append(extractTextFromNode(hitNodes[i])); |
| 106 unitedRects.unite(hitNodes[i]->pixelSnappedBoundingBox()); | 103 unitedRects.unite(hitNodes[i]->pixelSnappedBoundingBox()); |
| 107 } | 104 } |
| 108 | 105 |
| 109 return SmartClipData(bestNode, convertRectToWindow(unitedRects), collectedTe
xt.toString()); | 106 return SmartClipData(bestNode, m_frame->document()->view()->contentsToViewpo
rt(unitedRects), collectedText.toString()); |
| 110 } | 107 } |
| 111 | 108 |
| 112 float SmartClip::pageScaleFactor() | 109 float SmartClip::pageScaleFactor() |
| 113 { | 110 { |
| 114 return m_frame->page()->pageScaleFactor(); | 111 return m_frame->page()->pageScaleFactor(); |
| 115 } | 112 } |
| 116 | 113 |
| 117 // This function is a bit of a mystery. If you understand what it does, please | 114 // This function is a bit of a mystery. If you understand what it does, please |
| 118 // consider adding a more descriptive name. | 115 // consider adding a more descriptive name. |
| 119 Node* SmartClip::minNodeContainsNodes(Node* minNode, Node* newNode) | 116 Node* SmartClip::minNodeContainsNodes(Node* minNode, Node* newNode) |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 152 if (nodeRect.contains(newNodeRect)) { | 149 if (nodeRect.contains(newNodeRect)) { |
| 153 return node; | 150 return node; |
| 154 } | 151 } |
| 155 } | 152 } |
| 156 node = node->parentNode(); | 153 node = node->parentNode(); |
| 157 } | 154 } |
| 158 | 155 |
| 159 return nullptr; | 156 return nullptr; |
| 160 } | 157 } |
| 161 | 158 |
| 162 Node* SmartClip::findBestOverlappingNode(Node* rootNode, const IntRect& cropRect
) | 159 Node* SmartClip::findBestOverlappingNode(Node* rootNode, const IntRect& cropRect
InViewport) |
| 163 { | 160 { |
| 164 if (!rootNode) | 161 if (!rootNode) |
| 165 return nullptr; | 162 return nullptr; |
| 166 | 163 |
| 167 IntRect resizedCropRect = rootNode->document().view()->windowToContents(crop
Rect); | 164 IntRect resizedCropRect = convertToContentCoordinatesWithoutCollapsingToZero
(cropRectInViewport, rootNode->document().view()); |
| 168 | 165 |
| 169 Node* node = rootNode; | 166 Node* node = rootNode; |
| 170 Node* minNode = nullptr; | 167 Node* minNode = nullptr; |
| 171 | 168 |
| 172 while (node) { | 169 while (node) { |
| 173 IntRect nodeRect = node->pixelSnappedBoundingBox(); | 170 IntRect nodeRect = node->pixelSnappedBoundingBox(); |
| 174 | 171 |
| 175 if (node->isElementNode() && equalIgnoringCase(toElement(node)->fastGetA
ttribute(HTMLNames::aria_hiddenAttr), "true")) { | 172 if (node->isElementNode() && equalIgnoringCase(toElement(node)->fastGetA
ttribute(HTMLNames::aria_hiddenAttr), "true")) { |
| 176 node = NodeTraversal::nextSkippingChildren(*node, rootNode); | 173 node = NodeTraversal::nextSkippingChildren(*node, rootNode); |
| 177 continue; | 174 continue; |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 211 // image out of a CSS background, you're probably going to specify a height | 208 // image out of a CSS background, you're probably going to specify a height |
| 212 // or a width. On the other hand, if we've got a legit background image, | 209 // or a width. On the other hand, if we've got a legit background image, |
| 213 // it's very likely the height or the width will be set to auto. | 210 // it's very likely the height or the width will be set to auto. |
| 214 LayoutObject* renderer = node->layoutObject(); | 211 LayoutObject* renderer = node->layoutObject(); |
| 215 if (renderer && (renderer->style()->logicalHeight().isAuto() || renderer->st
yle()->logicalWidth().isAuto())) | 212 if (renderer && (renderer->style()->logicalHeight().isAuto() || renderer->st
yle()->logicalWidth().isAuto())) |
| 216 return true; | 213 return true; |
| 217 | 214 |
| 218 return false; | 215 return false; |
| 219 } | 216 } |
| 220 | 217 |
| 221 void SmartClip::collectOverlappingChildNodes(Node* parentNode, const IntRect& cr
opRect, WillBeHeapVector<RawPtrWillBeMember<Node>>& hitNodes) | 218 void SmartClip::collectOverlappingChildNodes(Node* parentNode, const IntRect& cr
opRectInViewport, WillBeHeapVector<RawPtrWillBeMember<Node>>& hitNodes) |
| 222 { | 219 { |
| 223 if (!parentNode) | 220 if (!parentNode) |
| 224 return; | 221 return; |
| 225 IntRect resizedCropRect = parentNode->document().view()->windowToContents(cr
opRect); | 222 IntRect resizedCropRect = convertToContentCoordinatesWithoutCollapsingToZero
(cropRectInViewport, parentNode->document().view()); |
| 226 for (Node* child = parentNode->firstChild(); child; child = child->nextSibli
ng()) { | 223 for (Node* child = parentNode->firstChild(); child; child = child->nextSibli
ng()) { |
| 227 IntRect childRect = child->pixelSnappedBoundingBox(); | 224 IntRect childRect = child->pixelSnappedBoundingBox(); |
| 228 if (resizedCropRect.intersects(childRect)) | 225 if (resizedCropRect.intersects(childRect)) |
| 229 hitNodes.append(child); | 226 hitNodes.append(child); |
| 230 } | 227 } |
| 231 } | 228 } |
| 232 | 229 |
| 233 IntRect SmartClip::convertRectToWindow(const IntRect& nodeRect) | |
| 234 { | |
| 235 IntRect result = m_frame->document()->view()->contentsToWindow(nodeRect); | |
| 236 result.scale(pageScaleFactor()); | |
| 237 return result; | |
| 238 } | |
| 239 | |
| 240 String SmartClip::extractTextFromNode(Node* node) | 230 String SmartClip::extractTextFromNode(Node* node) |
| 241 { | 231 { |
| 242 // Science has proven that no text nodes are ever positioned at y == -99999. | 232 // Science has proven that no text nodes are ever positioned at y == -99999. |
| 243 int prevYPos = -99999; | 233 int prevYPos = -99999; |
| 244 | 234 |
| 245 StringBuilder result; | 235 StringBuilder result; |
| 246 for (Node& currentNode : NodeTraversal::inclusiveDescendantsOf(*node)) { | 236 for (Node& currentNode : NodeTraversal::inclusiveDescendantsOf(*node)) { |
| 247 const LayoutStyle* style = currentNode.computedStyle(); | 237 const LayoutStyle* style = currentNode.computedStyle(); |
| 248 if (style && style->userSelect() == SELECT_NONE) | 238 if (style && style->userSelect() == SELECT_NONE) |
| 249 continue; | 239 continue; |
| (...skipping 18 matching lines...) Expand all Loading... |
| 268 | 258 |
| 269 result.append(nodeValue); | 259 result.append(nodeValue); |
| 270 } | 260 } |
| 271 } | 261 } |
| 272 } | 262 } |
| 273 | 263 |
| 274 return result.toString(); | 264 return result.toString(); |
| 275 } | 265 } |
| 276 | 266 |
| 277 } // namespace blink | 267 } // namespace blink |
| OLD | NEW |