1/* 2 Copyright (C) 2009-2010 ProFUSION embedded systems 3 Copyright (C) 2009-2010 Samsung Electronics 4 5 This library is free software; you can redistribute it and/or 6 modify it under the terms of the GNU Library General Public 7 License as published by the Free Software Foundation; either 8 version 2 of the License, or (at your option) any later version. 9 10 This library is distributed in the hope that it will be useful, 11 but WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 Library General Public License for more details. 14 15 You should have received a copy of the GNU Library General Public License 16 along with this library; see the file COPYING.LIB. If not, write to 17 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 18 Boston, MA 02110-1301, USA. 19*/ 20 21#include "config.h" 22#include "ewk_view.h" 23 24#include "TiledBackingStore.h" 25#include "ewk_frame_private.h" 26#include "ewk_private.h" 27#include "ewk_view_private.h" 28 29#include <Ecore_Evas.h> 30#include <Evas.h> 31#include <eina_safety_checks.h> 32#include <string.h> 33 34#if ENABLE(INSPECTOR) 35#include "InspectorController.h" 36#include "Page.h" 37#endif 38 39static Ewk_View_Smart_Class _parent_sc = EWK_VIEW_SMART_CLASS_INIT_NULL; 40 41static void _ewk_view_single_on_del(void* data, Evas*, Evas_Object*, void*) 42{ 43 Evas_Object* clip = (Evas_Object*)data; 44 evas_object_del(clip); 45} 46 47static void _ewk_view_single_smart_add(Evas_Object* ewkView) 48{ 49 Ewk_View_Smart_Data* smartData; 50 51 _parent_sc.sc.add(ewkView); 52 53 smartData = static_cast<Ewk_View_Smart_Data*>(evas_object_smart_data_get(ewkView)); 54 if (!smartData) 55 return; 56 57 Evas_Object* clip = evas_object_rectangle_add(smartData->base.evas); 58 evas_object_show(clip); 59 60 evas_object_event_callback_add 61 (smartData->backing_store, EVAS_CALLBACK_DEL, _ewk_view_single_on_del, clip); 62} 63 64static Evas_Object* _ewk_view_single_smart_backing_store_add(Ewk_View_Smart_Data* smartData) 65{ 66 Evas_Object* bs = evas_object_image_add(smartData->base.evas); 67 EINA_SAFETY_ON_NULL_RETURN_VAL(bs, 0); 68 const Ecore_Evas* ecoreEvas = ecore_evas_ecore_evas_get(smartData->base.evas); 69 const char* engine = ecore_evas_engine_name_get(ecoreEvas); 70 if (!strncmp(engine, "opengl_x11", strlen("opengl_x11"))) 71 evas_object_image_content_hint_set(bs, EVAS_IMAGE_CONTENT_HINT_DYNAMIC); 72 73 evas_object_image_alpha_set(bs, false); 74 evas_object_image_smooth_scale_set(bs, smartData->zoom_weak_smooth_scale); 75 76 return bs; 77} 78 79static void _ewk_view_single_smart_resize(Evas_Object* ewkView, Evas_Coord width, Evas_Coord height) 80{ 81 Ewk_View_Smart_Data* smartData = static_cast<Ewk_View_Smart_Data*>(evas_object_smart_data_get(ewkView)); 82 _parent_sc.sc.resize(ewkView, width, height); 83 84 if (!smartData) 85 return; 86 87 // these should be queued and processed in calculate as well! 88 evas_object_image_size_set(smartData->backing_store, width, height); 89 if (smartData->animated_zoom.zoom.current < 0.00001) { 90 Evas_Object* clip = evas_object_clip_get(smartData->backing_store); 91 Evas_Coord x, y, cw, ch; 92 evas_object_image_fill_set(smartData->backing_store, 0, 0, width, height); 93 evas_object_geometry_get(smartData->backing_store, &x, &y, 0, 0); 94 evas_object_move(clip, x, y); 95 ewk_frame_contents_size_get(smartData->main_frame, &cw, &ch); 96 if (width > cw) 97 width = cw; 98 if (height > ch) 99 height = ch; 100 evas_object_resize(clip, width, height); 101 } 102} 103 104static inline void _ewk_view_screen_move(uint32_t* image, size_t destinationX, size_t destinationY, size_t sourceX, size_t sourceY, size_t copyWidth, size_t copyHeight, size_t imageWidth) 105{ 106 uint32_t* sourceBegin = image + (imageWidth * sourceY) + sourceX; 107 uint32_t* destinationBegin = image + (imageWidth * destinationY) + destinationX; 108 109 size_t copyLength = copyWidth * 4; 110 const int moveLineUpDown = sourceY >= destinationY ? 1 : -1; 111 int startHeight = sourceY >= destinationY ? 0 : copyHeight - 1; 112 113 uint32_t* source, * destination; 114 if ((destinationX > sourceX && destinationX < sourceX + copyWidth) 115 || (destinationX < sourceX && destinationX + copyWidth > sourceX)) { 116 for (size_t i = 0; i < copyHeight; i++) { 117 source = sourceBegin + (imageWidth * startHeight); 118 destination = destinationBegin + (imageWidth * startHeight); 119 startHeight = startHeight + moveLineUpDown; 120 memmove(destination, source, copyLength); 121 } 122 } else { 123 for (size_t i = 0; i < copyHeight; i++) { 124 source = sourceBegin + (imageWidth * startHeight); 125 destination = destinationBegin + (imageWidth * startHeight); 126 startHeight = startHeight + moveLineUpDown; 127 memcpy(destination, source, copyLength); 128 } 129 } 130} 131 132static inline void _ewk_view_single_scroll_process_single(Ewk_View_Smart_Data* smartData, void* pixels, Evas_Coord width, Evas_Coord height, const WebCore::IntSize& scrollOffset, const WebCore::IntRect& rectToScroll) 133{ 134 int scrollX = rectToScroll.x(); 135 int scrollY = rectToScroll.y(); 136 int scrollWidth = rectToScroll.width(); 137 int scrollHeight = rectToScroll.height(); 138 139 DBG("%d,%d + %d,%d %+03d,%+03d, store: %p %dx%d", 140 scrollX, scrollY, scrollWidth, scrollHeight, scrollOffset.width(), scrollOffset.height(), pixels, width, height); 141 142 if (abs(scrollOffset.width()) >= scrollWidth || abs(scrollOffset.height()) >= scrollHeight) { 143 ewk_view_repaint_add(smartData->_priv, scrollX, scrollY, scrollWidth, scrollHeight); 144 return; 145 } 146 147 if (scrollX < 0) { 148 scrollWidth += scrollX; 149 scrollX = 0; 150 } 151 if (scrollY < 0) { 152 scrollHeight += scrollY; 153 scrollY = 0; 154 } 155 156 if (scrollX + scrollWidth > width) 157 scrollWidth = width - scrollX; 158 if (scrollY + scrollHeight > height) 159 scrollHeight = height - scrollY; 160 161 if (scrollWidth <= 0 || scrollHeight <= 0) 162 return; 163 164 int sourceX = scrollOffset.width() < 0 ? abs(scrollOffset.width()) : 0; 165 int sourceY = scrollOffset.height() < 0 ? abs(scrollOffset.height()) : 0; 166 int destinationX = scrollOffset.width() < 0 ? 0 : scrollOffset.width(); 167 int destinationY = scrollOffset.height() < 0 ? 0 : scrollOffset.height(); 168 int copyWidth = scrollWidth - abs(scrollOffset.width()); 169 int copyHeight = scrollHeight - abs(scrollOffset.height()); 170 if (scrollOffset.width() || scrollOffset.height()) { 171 _ewk_view_screen_move(static_cast<uint32_t*>(pixels), destinationX, destinationY, sourceX, sourceY, copyWidth, copyHeight, width); 172 evas_object_image_data_update_add(smartData->backing_store, destinationX, destinationY, copyWidth, copyHeight); 173 } 174 175 Eina_Rectangle verticalUpdate; 176 verticalUpdate.x = destinationX ? 0 : copyWidth - 1; 177 verticalUpdate.y = 0; 178 verticalUpdate.w = abs(scrollOffset.width()); 179 verticalUpdate.h = scrollHeight; 180 if (verticalUpdate.w && verticalUpdate.h) 181 ewk_view_repaint_add(smartData->_priv, verticalUpdate.x, verticalUpdate.y, verticalUpdate.w, verticalUpdate.h); 182 183 Eina_Rectangle horizontalUpdate; 184 horizontalUpdate.x = destinationX; 185 horizontalUpdate.y = destinationY ? 0 : copyHeight - 1; 186 horizontalUpdate.w = copyWidth; 187 horizontalUpdate.h = abs(scrollOffset.height()); 188 if (horizontalUpdate.w && horizontalUpdate.h) 189 ewk_view_repaint_add(smartData->_priv, horizontalUpdate.x, horizontalUpdate.y, horizontalUpdate.w, horizontalUpdate.h); 190} 191 192static Eina_Bool _ewk_view_single_smart_scrolls_process(Ewk_View_Smart_Data* smartData) 193{ 194 Evas_Coord imageWidth, imageHeight; 195 void* pixels = evas_object_image_data_get(smartData->backing_store, 1); 196 evas_object_image_size_get(smartData->backing_store, &imageWidth, &imageHeight); 197 198 const WTF::Vector<WebCore::IntSize>& scrollOffset = ewk_view_scroll_offsets_get(smartData->_priv); 199 const WTF::Vector<WebCore::IntRect>& rectsToScroll = ewk_view_scroll_rects_get(smartData->_priv); 200 for (size_t i = 0; i < scrollOffset.size(); ++i) 201 _ewk_view_single_scroll_process_single(smartData, pixels, imageWidth, imageHeight, scrollOffset[i], rectsToScroll[i]); 202 203 evas_object_image_data_set(smartData->backing_store, pixels); 204 205 return true; 206} 207 208static Eina_Bool _ewk_view_single_smart_repaints_process(Ewk_View_Smart_Data* smartData) 209{ 210 if (smartData->animated_zoom.zoom.current < 0.00001) { 211 Evas_Object* clip = evas_object_clip_get(smartData->backing_store); 212 213 // reset effects of zoom_weak_set() 214 evas_object_image_fill_set(smartData->backing_store, 0, 0, smartData->view.w, smartData->view.h); 215 evas_object_move(clip, smartData->view.x, smartData->view.y); 216 217 Evas_Coord width = smartData->view.w; 218 Evas_Coord height = smartData->view.h; 219 220 Evas_Coord centerWidth, centerHeight; 221 ewk_frame_contents_size_get(smartData->main_frame, ¢erWidth, ¢erHeight); 222 if (width > centerWidth) 223 width = centerWidth; 224 225 if (height > centerHeight) 226 height = centerHeight; 227 228 evas_object_resize(clip, width, height); 229 } 230 231 Evas_Coord imageWidth, imageHeight; 232 evas_object_image_size_get(smartData->backing_store, &imageWidth, &imageHeight); 233 234 Eina_Tiler* tiler = eina_tiler_new(imageWidth, imageHeight); 235 if (!tiler) { 236 ERR("could not create tiler %dx%d", imageWidth, imageHeight); 237 return false; 238 } 239 240 ewk_view_layout_if_needed_recursive(smartData->_priv); 241 242 size_t count; 243 const Eina_Rectangle* paintRequest = ewk_view_repaints_pop(smartData->_priv, &count); 244 const Eina_Rectangle* paintRequestEnd = paintRequest + count; 245 for (; paintRequest < paintRequestEnd; paintRequest++) 246 eina_tiler_rect_add(tiler, paintRequest); 247 248 Eina_Iterator* iterator = eina_tiler_iterator_new(tiler); 249 if (!iterator) { 250 ERR("could not get iterator for tiler"); 251 eina_tiler_free(tiler); 252 return false; 253 } 254 255#if USE(TILED_BACKING_STORE) 256 WebCore::Frame* mainFrame = EWKPrivate::coreFrame(smartData->main_frame); 257 if (mainFrame && mainFrame->tiledBackingStore()) 258 mainFrame->tiledBackingStore()->coverWithTilesIfNeeded(); 259#endif 260 261 Ewk_Paint_Context* context = ewk_paint_context_from_image_new(smartData->backing_store); 262 ewk_paint_context_save(context); 263 264 Eina_Rectangle* rect; 265 EINA_ITERATOR_FOREACH(iterator, rect) { 266 ewk_view_paint(smartData->_priv, context, rect); 267 evas_object_image_data_update_add(smartData->backing_store, rect->x, rect->y, rect->w, rect->h); 268 } 269 270#if ENABLE(INSPECTOR) 271 WebCore::Page* page = EWKPrivate::corePage(smartData->self); 272 if (page) { 273 WebCore::InspectorController* controller = page->inspectorController(); 274 if (controller->highlightedNode()) 275 controller->drawHighlight(*context->graphicContext); 276 } 277#endif 278 279 ewk_paint_context_restore(context); 280 ewk_paint_context_free(context); 281 282 eina_tiler_free(tiler); 283 eina_iterator_free(iterator); 284 285 return true; 286} 287 288static Eina_Bool _ewk_view_single_smart_zoom_weak_set(Ewk_View_Smart_Data* smartData, float zoom, Evas_Coord centerX, Evas_Coord centerY) 289{ 290 // TODO: review 291 float scale = zoom / smartData->animated_zoom.zoom.start; 292 Evas_Coord w = smartData->view.w * scale; 293 Evas_Coord h = smartData->view.h * scale; 294 Evas_Coord dx, dy, cw, ch; 295 Evas_Object* clip = evas_object_clip_get(smartData->backing_store); 296 297 ewk_frame_contents_size_get(smartData->main_frame, &cw, &ch); 298 if (smartData->view.w > 0 && smartData->view.h > 0) { 299 dx = (w * (smartData->view.w - centerX)) / smartData->view.w; 300 dy = (h * (smartData->view.h - centerY)) / smartData->view.h; 301 } else { 302 dx = 0; 303 dy = 0; 304 } 305 306 evas_object_image_fill_set(smartData->backing_store, centerX + dx, centerY + dy, w, h); 307 308 if (smartData->view.w > 0 && smartData->view.h > 0) { 309 dx = ((smartData->view.w - w) * centerX) / smartData->view.w; 310 dy = ((smartData->view.h - h) * centerY) / smartData->view.h; 311 } else { 312 dx = 0; 313 dy = 0; 314 } 315 evas_object_move(clip, smartData->view.x + dx, smartData->view.y + dy); 316 317 if (cw < smartData->view.w) 318 w = cw * scale; 319 if (ch < smartData->view.h) 320 h = ch * scale; 321 evas_object_resize(clip, w, h); 322 return true; 323} 324 325static void _ewk_view_single_smart_zoom_weak_smooth_scale_set(Ewk_View_Smart_Data* smartData, Eina_Bool smooth_scale) 326{ 327 evas_object_image_smooth_scale_set(smartData->backing_store, smooth_scale); 328} 329 330static void _ewk_view_single_smart_bg_color_set(Ewk_View_Smart_Data* smartData, unsigned char /*red*/, unsigned char /*green*/, unsigned char /*blue*/, unsigned char alpha) 331{ 332 evas_object_image_alpha_set(smartData->backing_store, alpha < 255); 333} 334 335Eina_Bool ewk_view_single_smart_set(Ewk_View_Smart_Class* api) 336{ 337 if (!ewk_view_base_smart_set(api)) 338 return false; 339 340 if (EINA_UNLIKELY(!_parent_sc.sc.add)) 341 ewk_view_base_smart_set(&_parent_sc); 342 343 api->sc.add = _ewk_view_single_smart_add; 344 api->sc.resize = _ewk_view_single_smart_resize; 345 346 api->backing_store_add = _ewk_view_single_smart_backing_store_add; 347 api->scrolls_process = _ewk_view_single_smart_scrolls_process; 348 api->repaints_process = _ewk_view_single_smart_repaints_process; 349 api->zoom_weak_set = _ewk_view_single_smart_zoom_weak_set; 350 api->zoom_weak_smooth_scale_set = _ewk_view_single_smart_zoom_weak_smooth_scale_set; 351 api->bg_color_set = _ewk_view_single_smart_bg_color_set; 352 353 return true; 354} 355 356static inline Evas_Smart* _ewk_view_single_smart_class_new(void) 357{ 358 static Ewk_View_Smart_Class api = EWK_VIEW_SMART_CLASS_INIT_NAME_VERSION(ewkViewSingleName); 359 static Evas_Smart* smart = 0; 360 361 if (EINA_UNLIKELY(!smart)) { 362 ewk_view_single_smart_set(&api); 363 smart = evas_smart_class_new(&api.sc); 364 } 365 366 return smart; 367} 368 369Evas_Object* ewk_view_single_add(Evas* canvas) 370{ 371 return evas_object_smart_add(canvas, _ewk_view_single_smart_class_new()); 372} 373