2 * Copyright (C) 2012 Samsung Electronics
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.
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.
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.
21 #include "SmartZoom.h"
23 #include "EwkViewImpl.h"
24 #include "PageClientImpl.h"
25 #include "ewk_view_private.h"
27 #if ENABLE(TOUCH_ADJUSTMENT)
28 #include <Elementary.h>
31 using namespace WebCore;
32 using namespace WebKit;
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 };
38 static IntPoint getNewScrollPosition(const IntPoint& scrollPosition, const IntPoint& basisPoint, double baseScaleFactor, double newScaleFactor)
40 if (fabs(baseScaleFactor) < numeric_limits<double>::epsilon())
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();
47 return IntPoint(newScrollX, newScrollY);
50 SmartZoom::SmartZoom(Evas_Object* viewWidget)
51 : m_viewWidget(viewWidget)
53 , m_baseScaleFactor(1)
55 , m_targetScaleFactor(1)
57 , m_baseScrollPosition()
61 m_viewImpl = EwkViewImpl::fromEvasObject(m_viewWidget);
64 SmartZoom::~SmartZoom()
69 void SmartZoom::start(int x, int y)
73 PageClientImpl* pageClientImpl = ewkViewGetPageClient(m_viewWidget);
74 EINA_SAFETY_ON_NULL_RETURN(pageClientImpl);
76 IntPoint position = m_viewImpl->transformFromScene().mapPoint(IntPoint(x, y));
78 #if ENABLE(TOUCH_ADJUSTMENT)
79 Evas_Coord size = elm_config_finger_size_get();
80 fingerSize = IntSize(size, size);
83 if (fabs(pageClientImpl->scaleFactor() - pageClientImpl->viewportConstraints().minimumScale) < numeric_limits<float>::epsilon())
84 pageClientImpl->page()->findZoomableAreaForPoint(position, fingerSize);
86 setZoomableArea(position, IntRect(IntPoint(), pageClientImpl->page()->contentsSize()));
89 void SmartZoom::setZoomableArea(const IntPoint& target, const IntRect& area)
94 PageClientImpl* pageClientImpl = ewkViewGetPageClient(m_viewWidget);
95 EINA_SAFETY_ON_NULL_RETURN(pageClientImpl);
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;
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);
108 if (zoomRect.x() > xMargin)
109 zoomRect.setX((zoomRect.x() - xMargin));
113 if (zoomRect.width() > 0)
114 zoomRect.setWidth((zoomRect.width() + widthMargin));
116 targetScaleFactor = static_cast<float>(viewRect.w) / static_cast<float>(zoomRect.width());
117 targetScaleFactor = pageClientImpl->adjustScaleWithViewport(targetScaleFactor);
119 zoomRect = IntRect(IntPoint(), pageClientImpl->page()->contentsSize());
122 IntPoint scrollPosition = pageClientImpl->scrollPosition();
123 float scaleFactor = pageClientImpl->scaleFactor();
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);
134 IntPoint zoomRectCenter(zoomRect.x() + zoomRect.width() * scaleFactor / 2,
135 zoomRect.y() + zoomRect.height() * scaleFactor / 2);
136 IntSize contentsSize = pageClientImpl->page()->contentsSize();
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);
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));
165 // Convert zoomRectCenter to Evas coordinate.
166 zoomRectCenter.scale(1 / scaleFactor, 1 / scaleFactor);
167 zoomRectCenter = m_viewImpl->transformToScene().mapPoint(zoomRectCenter);
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;
177 #if ENABLE(TIZEN_WEBKIT2_TILED_BACKING_STORE)
179 ecore_animator_del(m_scaleAnimator);
180 m_scaleAnimator = ecore_animator_add(scaleAnimatorCallback, this);
183 IntPoint newScrollPosition = getNewScrollPosition(m_baseScrollPosition, m_basisPoint, m_baseScaleFactor, m_targetScaleFactor);
184 pageClientImpl->page()->scale(m_targetScaleFactor, newScrollPosition);
188 void SmartZoom::stop()
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);
202 Eina_Bool SmartZoom::scaleAnimatorCallback(void* data)
204 return static_cast<SmartZoom*>(data)->process();
207 bool SmartZoom::process()
209 PageClientImpl* pageClientImpl = ewkViewGetPageClient(m_viewWidget);
210 EINA_SAFETY_ON_NULL_RETURN_VAL(pageClientImpl, false);
212 if (m_scaleIndex < 0) {
213 IntPoint newScrollPosition = getNewScrollPosition(m_baseScrollPosition, m_basisPoint, m_baseScaleFactor, m_newScaleFactor);
214 pageClientImpl->page()->scale(m_newScaleFactor, newScrollPosition);
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);