• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2013 Google Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
8  *     * Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  *     * Redistributions in binary form must reproduce the above
11  * copyright notice, this list of conditions and the following disclaimer
12  * in the documentation and/or other materials provided with the
13  * distribution.
14  *     * Neither the name of Google Inc. nor the names of its
15  * contributors may be used to endorse or promote products derived from
16  * this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30 
31 #include "config.h"
32 #include "web/ViewportAnchor.h"
33 
34 #include "core/dom/ContainerNode.h"
35 #include "core/dom/Node.h"
36 #include "core/page/EventHandler.h"
37 #include "core/rendering/HitTestResult.h"
38 
39 using namespace WebCore;
40 
41 namespace blink {
42 
43 namespace {
44 
45 static const float viewportAnchorRelativeEpsilon = 0.1f;
46 static const int viewportToNodeMaxRelativeArea = 2;
47 
48 template <typename RectType>
area(const RectType & rect)49 int area(const RectType& rect) {
50     return rect.width() * rect.height();
51 }
52 
findNonEmptyAnchorNode(const IntPoint & point,const IntRect & viewRect,EventHandler * eventHandler)53 Node* findNonEmptyAnchorNode(const IntPoint& point, const IntRect& viewRect, EventHandler* eventHandler)
54 {
55     Node* node = eventHandler->hitTestResultAtPoint(point, HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::ConfusingAndOftenMisusedDisallowShadowContent).innerNode();
56 
57     // If the node bounding box is sufficiently large, make a single attempt to
58     // find a smaller node; the larger the node bounds, the greater the
59     // variability under resize.
60     const int maxNodeArea = area(viewRect) * viewportToNodeMaxRelativeArea;
61     if (node && area(node->boundingBox()) > maxNodeArea) {
62         IntSize pointOffset = viewRect.size();
63         pointOffset.scale(viewportAnchorRelativeEpsilon);
64         node = eventHandler->hitTestResultAtPoint(point + pointOffset, HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::ConfusingAndOftenMisusedDisallowShadowContent).innerNode();
65     }
66 
67     while (node && node->boundingBox().isEmpty())
68         node = node->parentNode();
69 
70     return node;
71 }
72 
73 } // namespace
74 
ViewportAnchor(EventHandler * eventHandler)75 ViewportAnchor::ViewportAnchor(EventHandler* eventHandler)
76     : m_eventHandler(eventHandler) { }
77 
setAnchor(const IntRect & viewRect,const FloatSize & anchorInViewCoords)78 void ViewportAnchor::setAnchor(const IntRect& viewRect, const FloatSize& anchorInViewCoords)
79 {
80     m_viewRect = viewRect;
81     m_anchorNode.clear();
82     m_anchorNodeBounds = LayoutRect();
83     m_anchorInNodeCoords = FloatSize();
84     m_anchorInViewCoords = anchorInViewCoords;
85 
86     if (viewRect.isEmpty())
87         return;
88 
89     // Preserve origins at the absolute screen origin
90     if (viewRect.location() == IntPoint::zero())
91         return;
92 
93     FloatSize anchorOffset = viewRect.size();
94     anchorOffset.scale(anchorInViewCoords.width(), anchorInViewCoords.height());
95     const FloatPoint anchorPoint = FloatPoint(viewRect.location()) + anchorOffset;
96 
97     Node* node = findNonEmptyAnchorNode(flooredIntPoint(anchorPoint), viewRect, m_eventHandler);
98     if (!node)
99         return;
100 
101     m_anchorNode = node;
102     m_anchorNodeBounds = node->boundingBox();
103     m_anchorInNodeCoords = anchorPoint - m_anchorNodeBounds.location();
104     m_anchorInNodeCoords.scale(1.f / m_anchorNodeBounds.width(), 1.f / m_anchorNodeBounds.height());
105 }
106 
computeOrigin(const IntSize & currentViewSize) const107 IntPoint ViewportAnchor::computeOrigin(const IntSize& currentViewSize) const
108 {
109     if (!m_anchorNode || !m_anchorNode->inDocument())
110         return m_viewRect.location();
111 
112     const LayoutRect currentNodeBounds = m_anchorNode->boundingBox();
113     if (m_anchorNodeBounds == currentNodeBounds)
114         return m_viewRect.location();
115 
116     // Compute the new anchor point relative to the node position
117     FloatSize anchorOffsetFromNode = currentNodeBounds.size();
118     anchorOffsetFromNode.scale(m_anchorInNodeCoords.width(), m_anchorInNodeCoords.height());
119     FloatPoint anchorPoint = currentNodeBounds.location() + anchorOffsetFromNode;
120 
121     // Compute the new origin point relative to the new anchor point
122     FloatSize anchorOffsetFromOrigin = currentViewSize;
123     anchorOffsetFromOrigin.scale(m_anchorInViewCoords.width(), m_anchorInViewCoords.height());
124     return flooredIntPoint(anchorPoint - anchorOffsetFromOrigin);
125 }
126 
127 } // namespace blink
128