Tizen 2.1 base
[framework/web/webkit-efl.git] / Source / WebKit2 / UIProcess / API / efl / tizen / SmartZoom.cpp
1 /*
2  * Copyright (C) 2012 Samsung Electronics
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public License
15  * along with this program; see the file COPYING.LIB.  If not, write to
16  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17  * Boston, MA 02110-1301, USA.
18  */
19
20 #include "config.h"
21 #include "SmartZoom.h"
22
23 #include "EwkViewImpl.h"
24 #include "PageClientImpl.h"
25 #include "ewk_view_private.h"
26
27 #if ENABLE(TOUCH_ADJUSTMENT)
28 #include <Elementary.h>
29 #endif
30
31 using namespace WebCore;
32 using namespace WebKit;
33 using namespace std;
34
35 const float SmartZoom::s_cosine[s_numberOfCosineValue] =
36 { 1.0f, 0.99f, 0.96f, 0.93f, 0.88f, 0.82f, 0.75f, 0.67f, 0.59f, 0.5f, 0.41f, 0.33f, 0.25f, 0.18f, 0.12f, 0.07f, 0.01f };
37
38 static IntPoint getNewScrollPosition(const IntPoint& scrollPosition, const IntPoint& basisPoint, double baseScaleFactor, double newScaleFactor)
39 {
40     if (fabs(baseScaleFactor) < numeric_limits<double>::epsilon())
41         return IntPoint();
42
43     double scaleDifference = newScaleFactor / baseScaleFactor;
44     int newScrollX = (scrollPosition.x() + basisPoint.x()) * scaleDifference - basisPoint.x();
45     int newScrollY = (scrollPosition.y() + basisPoint.y()) * scaleDifference - basisPoint.y();
46
47     return IntPoint(newScrollX, newScrollY);
48 }
49
50 SmartZoom::SmartZoom(Evas_Object* viewWidget)
51     : m_viewWidget(viewWidget)
52     , m_scaleAnimator()
53     , m_baseScaleFactor(1)
54     , m_newScaleFactor(1)
55     , m_targetScaleFactor(1)
56     , m_basisPoint()
57     , m_baseScrollPosition()
58     , m_scaleIndex(0)
59     , m_isStarted(false)
60 {
61     m_viewImpl = EwkViewImpl::fromEvasObject(m_viewWidget);
62 }
63
64 SmartZoom::~SmartZoom()
65 {
66     stop();
67 }
68
69 void SmartZoom::start(int x, int y)
70 {
71     m_isStarted = true;
72
73     PageClientImpl* pageClientImpl = ewkViewGetPageClient(m_viewWidget);
74     EINA_SAFETY_ON_NULL_RETURN(pageClientImpl);
75
76     IntPoint position = m_viewImpl->transformFromScene().mapPoint(IntPoint(x, y));
77     IntSize fingerSize;
78 #if ENABLE(TOUCH_ADJUSTMENT)
79     Evas_Coord size = elm_config_finger_size_get();
80     fingerSize = IntSize(size, size);
81 #endif
82
83     if (fabs(pageClientImpl->scaleFactor() - pageClientImpl->viewportConstraints().minimumScale) < numeric_limits<float>::epsilon())
84         pageClientImpl->page()->findZoomableAreaForPoint(position, fingerSize);
85     else
86         setZoomableArea(position, IntRect(IntPoint(), pageClientImpl->page()->contentsSize()));
87 }
88
89 void SmartZoom::setZoomableArea(const IntPoint& target, const IntRect& area)
90 {
91     if (!m_isStarted)
92         return;
93
94     PageClientImpl* pageClientImpl = ewkViewGetPageClient(m_viewWidget);
95     EINA_SAFETY_ON_NULL_RETURN(pageClientImpl);
96
97     IntRect zoomRect = area;
98     Eina_Rectangle viewRect;
99     evas_object_geometry_get(m_viewWidget, &viewRect.x, &viewRect.y, &viewRect.w, &viewRect.h);
100     float minimumScale = pageClientImpl->viewportConstraints().minimumScale;
101     float targetScaleFactor = minimumScale;
102
103     if (zoomRect.width()) {
104         // Add the margin for looking good.
105         int xMargin = static_cast<int>(s_xMargin / minimumScale);
106         int widthMargin = static_cast<int>(s_widthMargin / minimumScale);
107
108         if (zoomRect.x() > xMargin)
109             zoomRect.setX((zoomRect.x() - xMargin));
110         else
111             zoomRect.setX(0);
112
113         if (zoomRect.width() > 0)
114             zoomRect.setWidth((zoomRect.width() + widthMargin));
115
116         targetScaleFactor = static_cast<float>(viewRect.w) / static_cast<float>(zoomRect.width());
117         targetScaleFactor = pageClientImpl->adjustScaleWithViewport(targetScaleFactor);
118     } else {
119         zoomRect = IntRect(IntPoint(), pageClientImpl->page()->contentsSize());
120     }
121
122     IntPoint scrollPosition = pageClientImpl->scrollPosition();
123     float scaleFactor = pageClientImpl->scaleFactor();
124
125     // Adjust to contents boundary.
126 #if ENABLE(TIZEN_WEBKIT2_TILED_BACKING_STORE)
127     // We have to multiply with scaleFactor for TILED_BACKING_STORE because it has its own
128     // scaleFactor only in the UIProcess.
129     IntPoint zoomRectCenter = zoomRect.center();
130     zoomRectCenter.scale(scaleFactor, scaleFactor);
131     IntSize contentsSize = pageClientImpl->page()->contentsSize();
132     contentsSize.scale(scaleFactor);
133 #else
134     IntPoint zoomRectCenter(zoomRect.x() + zoomRect.width() * scaleFactor / 2,
135                                       zoomRect.y() + zoomRect.height() * scaleFactor / 2);
136     IntSize contentsSize = pageClientImpl->page()->contentsSize();
137 #endif
138     // We have to adjust y position to not hide selected region.
139     if (zoomRect.height() * targetScaleFactor > viewRect.h)
140         zoomRectCenter.setY(target.y() * scaleFactor);
141
142     float scaleDifference = targetScaleFactor / scaleFactor;
143     IntPoint viewCenter(viewRect.x + (viewRect.w / 2), viewRect.y + (viewRect.h / 2));
144     IntPoint positionToGo = viewCenter;
145     // Get amount of contents on the left, right, top and bottom side of zoomRectCenter after zooming.
146     int leftContents = zoomRectCenter.x() * scaleDifference;
147     int rightContents = contentsSize.width() * scaleDifference - leftContents;
148     int topContents = zoomRectCenter.y() * scaleDifference;
149     int bottomContents = contentsSize.height() * scaleDifference - topContents;
150     // Get amount of view on the left, right, top and bottom side of viewCenter.
151     int leftView = viewCenter.x() - viewRect.x;
152     int rightView = viewRect.w - leftView;
153     int topView = viewCenter.y() - viewRect.y;
154     int bottomView = viewRect.h - topView;
155     // Adjust position to go.
156     if (leftContents < leftView)
157         positionToGo.setX(viewCenter.x() - (leftView - leftContents));
158     else if (rightContents < rightView)
159         positionToGo.setX(viewCenter.x() + (rightView - rightContents));
160     if (topContents < topView)
161         positionToGo.setY(viewCenter.y() - (topView - topContents));
162     else if (bottomContents < bottomView)
163         positionToGo.setY(viewCenter.y() + (bottomView - bottomContents));
164
165     // Convert zoomRectCenter to Evas coordinate.
166     zoomRectCenter.scale(1 / scaleFactor, 1 / scaleFactor);
167     zoomRectCenter = m_viewImpl->transformToScene().mapPoint(zoomRectCenter);
168
169     // Set initial values for zooming.
170     m_basisPoint.setX((positionToGo.x() - scaleDifference * zoomRectCenter.x()) / (1 - scaleDifference) - viewRect.x);
171     m_basisPoint.setY((positionToGo.y() - scaleDifference * zoomRectCenter.y()) / (1 - scaleDifference) - viewRect.y);
172     m_baseScaleFactor = scaleFactor;
173     m_baseScrollPosition = scrollPosition;
174     m_targetScaleFactor = targetScaleFactor;
175     m_scaleIndex = s_numberOfCosineValue - 1;
176
177 #if ENABLE(TIZEN_WEBKIT2_TILED_BACKING_STORE)
178     if (m_scaleAnimator)
179         ecore_animator_del(m_scaleAnimator);
180     m_scaleAnimator = ecore_animator_add(scaleAnimatorCallback, this);
181     process();
182 #else
183     IntPoint newScrollPosition = getNewScrollPosition(m_baseScrollPosition, m_basisPoint, m_baseScaleFactor, m_targetScaleFactor);
184     pageClientImpl->page()->scale(m_targetScaleFactor, newScrollPosition);
185 #endif
186 }
187
188 void SmartZoom::stop()
189 {
190     m_isStarted = false;
191
192     if (m_scaleAnimator) {
193         ecore_animator_del(m_scaleAnimator);
194         IntPoint newScrollPosition = getNewScrollPosition(m_baseScrollPosition, m_basisPoint, m_baseScaleFactor, m_newScaleFactor);
195         PageClientImpl* pageClientImpl = ewkViewGetPageClient(m_viewWidget);
196         EINA_SAFETY_ON_NULL_RETURN(pageClientImpl);
197         pageClientImpl->page()->scale(m_newScaleFactor, newScrollPosition);
198         m_scaleAnimator = 0;
199     }
200 }
201
202 Eina_Bool SmartZoom::scaleAnimatorCallback(void* data)
203 {
204     return static_cast<SmartZoom*>(data)->process();
205 }
206
207 bool SmartZoom::process()
208 {
209     PageClientImpl* pageClientImpl = ewkViewGetPageClient(m_viewWidget);
210     EINA_SAFETY_ON_NULL_RETURN_VAL(pageClientImpl, false);
211
212     if (m_scaleIndex < 0) {
213         IntPoint newScrollPosition = getNewScrollPosition(m_baseScrollPosition, m_basisPoint, m_baseScaleFactor, m_newScaleFactor);
214         pageClientImpl->page()->scale(m_newScaleFactor, newScrollPosition);
215         m_scaleAnimator = 0;
216         return false;
217     }
218
219     m_newScaleFactor = m_baseScaleFactor + ((m_targetScaleFactor - m_baseScaleFactor) * s_cosine[m_scaleIndex]);
220     IntPoint newScrollPosition = getNewScrollPosition(m_baseScrollPosition, m_basisPoint, m_baseScaleFactor, m_newScaleFactor);
221     pageClientImpl->page()->scaleImage(m_newScaleFactor, newScrollPosition);
222
223     m_scaleIndex--;
224     return true;
225 }