ewk_view_tiled.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377
  1. /*
  2. Copyright (C) 2009-2010 Samsung Electronics
  3. Copyright (C) 2009-2010 ProFUSION embedded systems
  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. This library is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. Library General Public License for more details.
  12. You should have received a copy of the GNU Library General Public License
  13. along with this library; see the file COPYING.LIB. If not, write to
  14. the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
  15. Boston, MA 02110-1301, USA.
  16. */
  17. #include "config.h"
  18. #include "ewk_view.h"
  19. #include "ewk_private.h"
  20. #include "ewk_tiled_backing_store_private.h"
  21. #include "ewk_view_private.h"
  22. #include <Evas.h>
  23. #include <eina_safety_checks.h>
  24. static Ewk_View_Smart_Class _parent_sc = EWK_VIEW_SMART_CLASS_INIT_NULL;
  25. static bool _ewk_view_tiled_render_cb(void* data, Ewk_Tile* tile, const Eina_Rectangle* area)
  26. {
  27. Ewk_View_Private_Data* priv = static_cast<Ewk_View_Private_Data*>(data);
  28. Eina_Rectangle rect = {area->x + tile->x, area->y + tile->y, area->w, area->h};
  29. uint8_t* pixels = static_cast<uint8_t*>(evas_object_image_data_get(tile->image, true));
  30. Ewk_Paint_Context* context = ewk_paint_context_from_image_data_new(pixels, tile->width, tile->height, tile->cspace);
  31. ewk_paint_context_translate(context, -tile->x, -tile->y);
  32. bool result = ewk_view_paint_contents(priv, context, &rect);
  33. ewk_paint_context_free(context);
  34. evas_object_image_data_set(tile->image, pixels);
  35. return result;
  36. }
  37. static void* _ewk_view_tiled_updates_process_pre(void* data, Evas_Object*)
  38. {
  39. Ewk_View_Private_Data* priv = static_cast<Ewk_View_Private_Data*>(data);
  40. ewk_view_layout_if_needed_recursive(priv);
  41. return 0;
  42. }
  43. static Evas_Object* _ewk_view_tiled_smart_backing_store_add(Ewk_View_Smart_Data* smartData)
  44. {
  45. Evas_Object* backingStore = ewk_tiled_backing_store_add(smartData->base.evas);
  46. ewk_tiled_backing_store_render_cb_set(backingStore, _ewk_view_tiled_render_cb, smartData->_priv);
  47. ewk_tiled_backing_store_updates_process_pre_set
  48. (backingStore, _ewk_view_tiled_updates_process_pre, smartData->_priv);
  49. return backingStore;
  50. }
  51. static void
  52. _ewk_view_tiled_contents_size_changed_cb(void* data, Evas_Object*, void* eventInfo)
  53. {
  54. Evas_Coord* size = static_cast<Evas_Coord*>(eventInfo);
  55. Ewk_View_Smart_Data* smartData = static_cast<Ewk_View_Smart_Data*>(data);
  56. ewk_tiled_backing_store_contents_resize
  57. (smartData->backing_store, size[0], size[1]);
  58. }
  59. static void _ewk_view_tiled_smart_add(Evas_Object* ewkView)
  60. {
  61. Ewk_View_Smart_Data* smartData;
  62. _parent_sc.sc.add(ewkView);
  63. smartData = static_cast<Ewk_View_Smart_Data*>(evas_object_smart_data_get(ewkView));
  64. if (!smartData)
  65. return;
  66. evas_object_smart_callback_add(
  67. smartData->main_frame, "contents,size,changed",
  68. _ewk_view_tiled_contents_size_changed_cb, smartData);
  69. }
  70. static Eina_Bool _ewk_view_tiled_smart_scrolls_process(Ewk_View_Smart_Data* smartData)
  71. {
  72. const WTF::Vector<WebCore::IntSize>& scrollOffset = ewk_view_scroll_offsets_get(smartData->_priv);
  73. for (size_t i = 0; i < scrollOffset.size(); ++i)
  74. ewk_tiled_backing_store_scroll_full_offset_add(smartData->backing_store, scrollOffset[i].width(), scrollOffset[i].height());
  75. return true;
  76. }
  77. static Eina_Bool _ewk_view_tiled_smart_repaints_process(Ewk_View_Smart_Data* smartData)
  78. {
  79. const Eina_Rectangle* paintRect, * endOfpaintRect;
  80. size_t count;
  81. int scrollX, scrollY;
  82. ewk_frame_scroll_pos_get(smartData->main_frame, &scrollX, &scrollY);
  83. paintRect = ewk_view_repaints_pop(smartData->_priv, &count);
  84. endOfpaintRect = paintRect + count;
  85. for (; paintRect < endOfpaintRect; paintRect++) {
  86. Eina_Rectangle rect;
  87. rect.x = paintRect->x + scrollX;
  88. rect.y = paintRect->y + scrollY;
  89. rect.w = paintRect->w;
  90. rect.h = paintRect->h;
  91. ewk_tiled_backing_store_update(smartData->backing_store, &rect);
  92. }
  93. ewk_tiled_backing_store_updates_process(smartData->backing_store);
  94. return true;
  95. }
  96. static Eina_Bool _ewk_view_tiled_smart_contents_resize(Ewk_View_Smart_Data* smartData, int width, int height)
  97. {
  98. ewk_tiled_backing_store_contents_resize(smartData->backing_store, width, height);
  99. return true;
  100. }
  101. static Eina_Bool _ewk_view_tiled_smart_zoom_set(Ewk_View_Smart_Data* smartData, float zoom, Evas_Coord centerX, Evas_Coord centerY)
  102. {
  103. Evas_Coord x, y, width, height;
  104. Eina_Bool result;
  105. result = ewk_tiled_backing_store_zoom_set(smartData->backing_store,
  106. &zoom, centerX, centerY, &x, &y);
  107. if (!result)
  108. return result;
  109. ewk_tiled_backing_store_disabled_update_set(smartData->backing_store, true);
  110. result = _parent_sc.zoom_set(smartData, zoom, centerX, centerY);
  111. ewk_frame_scroll_set(smartData->main_frame, -x, -y);
  112. ewk_frame_scroll_size_get(smartData->main_frame, &width, &height);
  113. ewk_tiled_backing_store_fix_offsets(smartData->backing_store, width, height);
  114. ewk_view_scrolls_process(smartData);
  115. evas_object_smart_calculate(smartData->backing_store);
  116. evas_object_smart_calculate(smartData->self);
  117. ewk_tiled_backing_store_disabled_update_set(smartData->backing_store, false);
  118. return result;
  119. }
  120. static Eina_Bool _ewk_view_tiled_smart_zoom_weak_set(Ewk_View_Smart_Data* smartData, float zoom, Evas_Coord centerX, Evas_Coord centerY)
  121. {
  122. return ewk_tiled_backing_store_zoom_weak_set(smartData->backing_store, zoom, centerX, centerY);
  123. }
  124. static void _ewk_view_tiled_smart_zoom_weak_smooth_scale_set(Ewk_View_Smart_Data* smartData, Eina_Bool smoothScale)
  125. {
  126. ewk_tiled_backing_store_zoom_weak_smooth_scale_set(smartData->backing_store, smoothScale);
  127. }
  128. static void _ewk_view_tiled_smart_bg_color_set(Ewk_View_Smart_Data* smartData, unsigned char /*red*/, unsigned char /*green*/, unsigned char /*blue*/, unsigned char alpha)
  129. {
  130. ewk_tiled_backing_store_alpha_set(smartData->backing_store, alpha < 255);
  131. }
  132. static void _ewk_view_tiled_smart_flush(Ewk_View_Smart_Data* smartData)
  133. {
  134. ewk_tiled_backing_store_flush(smartData->backing_store);
  135. _parent_sc.flush(smartData);
  136. }
  137. static Eina_Bool _ewk_view_tiled_smart_pre_render_region(Ewk_View_Smart_Data* smartData, Evas_Coord x, Evas_Coord y, Evas_Coord width, Evas_Coord height, float zoom)
  138. {
  139. return ewk_tiled_backing_store_pre_render_region
  140. (smartData->backing_store, x, y, width, height, zoom);
  141. }
  142. static Eina_Bool _ewk_view_tiled_smart_pre_render_relative_radius(Ewk_View_Smart_Data* smartData, unsigned int n, float zoom)
  143. {
  144. return ewk_tiled_backing_store_pre_render_relative_radius
  145. (smartData->backing_store, n, zoom);
  146. }
  147. static inline int _ewk_view_tiled_rect_collision_check(Eina_Rectangle destination, Eina_Rectangle source)
  148. {
  149. int direction = 0;
  150. if (destination.x < source.x)
  151. direction = direction | (1 << 0); // 0 bit shift, left
  152. if (destination.y < source.y)
  153. direction = direction | (1 << 1); // 1 bit shift, top
  154. if (destination.x + destination.w > source.x + source.w)
  155. direction = direction | (1 << 2); // 2 bit shift, right
  156. if (destination.y + destination.h > source.y + source.h)
  157. direction = direction | (1 << 3); // 3 bit shift, bottom
  158. DBG("check collision %d\r\n", direction);
  159. return direction;
  160. }
  161. static inline void _ewk_view_tiled_rect_collision_resolve(int direction, Eina_Rectangle* destination, Eina_Rectangle source)
  162. {
  163. if (direction & (1 << 0)) // 0 bit shift, left
  164. destination->x = source.x;
  165. if (direction & (1 << 1)) // 1 bit shift, top
  166. destination->y = source.y;
  167. if (direction & (1 << 2)) // 2 bit shift, right
  168. destination->x = destination->x - ((destination->x + destination->w) - (source.x + source.w));
  169. if (direction & (1 << 3)) // 3 bit shift, bottom
  170. destination->y = destination->y - ((destination->y + destination->h) - (source.y + source.h));
  171. }
  172. static Eina_Bool _ewk_view_tiled_smart_pre_render_start(Ewk_View_Smart_Data* smartData)
  173. {
  174. int contentWidth, contentHeight;
  175. ewk_frame_contents_size_get(smartData->main_frame, &contentWidth, &contentHeight);
  176. int viewX, viewY, viewWidth, viewHeight;
  177. ewk_frame_visible_content_geometry_get(smartData->main_frame, false, &viewX, &viewY, &viewWidth, &viewHeight);
  178. if (viewWidth <= 0 || viewHeight <= 0 || contentWidth <= 0 || contentHeight <= 0)
  179. return false;
  180. if (viewWidth >= contentWidth && viewHeight >= contentHeight)
  181. return false;
  182. int previousViewX, previousViewY;
  183. previousViewX = smartData->previousView.x;
  184. previousViewY = smartData->previousView.y;
  185. if (previousViewX < 0 || previousViewX > contentWidth || previousViewY < 0 || previousViewY > contentHeight)
  186. previousViewX = previousViewY = 0;
  187. float currentViewZoom = ewk_view_zoom_get(smartData->self);
  188. // pre-render works when two conditions are met.
  189. // zoom has been changed.
  190. // and the view has been moved more than tile size.
  191. if (abs(previousViewX - viewX) < defaultTileWidth
  192. && abs(previousViewY - viewY) < defaultTileHeigth
  193. && smartData->previousView.zoom == currentViewZoom) {
  194. return false;
  195. }
  196. // store previous view position and zoom.
  197. smartData->previousView.x = viewX;
  198. smartData->previousView.y = viewY;
  199. smartData->previousView.zoom = currentViewZoom;
  200. // cancelling previous pre-rendering list if exists.
  201. ewk_view_pre_render_cancel(smartData->self);
  202. Ewk_Tile_Unused_Cache* tileUnusedCache = ewk_view_tiled_unused_cache_get(smartData->self);
  203. int maxMemory = ewk_tile_unused_cache_max_get(tileUnusedCache);
  204. if (maxMemory <= viewWidth * viewHeight * EWK_ARGB_BYTES_SIZE)
  205. return false;
  206. Eina_Rectangle viewRect = {viewX, viewY, viewWidth, viewHeight};
  207. Eina_Rectangle contentRect = {0, 0, contentWidth, contentHeight};
  208. // get a base render rect.
  209. const int contentMemory = contentWidth * contentHeight * EWK_ARGB_BYTES_SIZE;
  210. // get render rect's width and height.
  211. Eina_Rectangle renderRect;
  212. if (maxMemory > contentMemory)
  213. renderRect = contentRect;
  214. else {
  215. // Make a base rectangle as big as possible with using maxMemory.
  216. // and then reshape the base rectangle to fit to contents.
  217. const int baseSize = static_cast<int>(sqrt(maxMemory / 4.0f));
  218. const float widthRate = (viewRect.w + (defaultTileWidth * 2)) / static_cast<float>(baseSize);
  219. const float heightRate = baseSize / static_cast<float>(contentHeight);
  220. const float rectRate = std::max(widthRate, heightRate);
  221. renderRect.w = static_cast<int>(baseSize * rectRate);
  222. renderRect.h = static_cast<int>(baseSize / rectRate);
  223. renderRect.x = viewRect.x + (viewRect.w / 2) - (renderRect.w / 2);
  224. renderRect.y = viewRect.y + (viewRect.h / 2) - (renderRect.h / 2);
  225. // reposition of renderRect, if the renderRect overlapped the content rect, this code moves the renderRect inside the content rect.
  226. int collisionSide = _ewk_view_tiled_rect_collision_check(renderRect, contentRect);
  227. if (collisionSide > 0)
  228. _ewk_view_tiled_rect_collision_resolve(collisionSide, &renderRect, contentRect);
  229. // check abnormal render rect
  230. if (renderRect.x < 0)
  231. renderRect.x = 0;
  232. if (renderRect.y < 0)
  233. renderRect.y = 0;
  234. if (renderRect.w > contentWidth)
  235. renderRect.w = contentWidth;
  236. if (renderRect.h > contentHeight)
  237. renderRect.h = contentHeight;
  238. }
  239. // enqueue tiles into tiled backing store in spiral order.
  240. ewk_tiled_backing_store_pre_render_spiral_queue(smartData->backing_store, &viewRect, &renderRect, maxMemory, currentViewZoom);
  241. return true;
  242. }
  243. static void _ewk_view_tiled_smart_pre_render_cancel(Ewk_View_Smart_Data* smartData)
  244. {
  245. ewk_tiled_backing_store_pre_render_cancel(smartData->backing_store);
  246. }
  247. static Eina_Bool _ewk_view_tiled_smart_disable_render(Ewk_View_Smart_Data* smartData)
  248. {
  249. return ewk_tiled_backing_store_disable_render(smartData->backing_store);
  250. }
  251. static Eina_Bool _ewk_view_tiled_smart_enable_render(Ewk_View_Smart_Data* smartData)
  252. {
  253. return ewk_tiled_backing_store_enable_render(smartData->backing_store);
  254. }
  255. Eina_Bool ewk_view_tiled_smart_set(Ewk_View_Smart_Class* api)
  256. {
  257. if (!ewk_view_base_smart_set(api))
  258. return false;
  259. if (EINA_UNLIKELY(!_parent_sc.sc.add)) {
  260. _parent_sc.sc.name = ewkViewTiledName;
  261. ewk_view_base_smart_set(&_parent_sc);
  262. api->sc.parent = reinterpret_cast<Evas_Smart_Class*>(&_parent_sc);
  263. }
  264. api->sc.add = _ewk_view_tiled_smart_add;
  265. api->backing_store_add = _ewk_view_tiled_smart_backing_store_add;
  266. api->scrolls_process = _ewk_view_tiled_smart_scrolls_process;
  267. api->repaints_process = _ewk_view_tiled_smart_repaints_process;
  268. api->contents_resize = _ewk_view_tiled_smart_contents_resize;
  269. api->zoom_set = _ewk_view_tiled_smart_zoom_set;
  270. api->zoom_weak_set = _ewk_view_tiled_smart_zoom_weak_set;
  271. api->zoom_weak_smooth_scale_set = _ewk_view_tiled_smart_zoom_weak_smooth_scale_set;
  272. api->bg_color_set = _ewk_view_tiled_smart_bg_color_set;
  273. api->flush = _ewk_view_tiled_smart_flush;
  274. api->pre_render_region = _ewk_view_tiled_smart_pre_render_region;
  275. api->pre_render_relative_radius = _ewk_view_tiled_smart_pre_render_relative_radius;
  276. api->pre_render_start = _ewk_view_tiled_smart_pre_render_start;
  277. api->pre_render_cancel = _ewk_view_tiled_smart_pre_render_cancel;
  278. api->disable_render = _ewk_view_tiled_smart_disable_render;
  279. api->enable_render = _ewk_view_tiled_smart_enable_render;
  280. return true;
  281. }
  282. static inline Evas_Smart* _ewk_view_tiled_smart_class_new(void)
  283. {
  284. static Ewk_View_Smart_Class api = EWK_VIEW_SMART_CLASS_INIT_NAME_VERSION(ewkViewTiledName);
  285. static Evas_Smart* smart = 0;
  286. if (EINA_UNLIKELY(!smart)) {
  287. ewk_view_tiled_smart_set(&api);
  288. smart = evas_smart_class_new(&api.sc);
  289. }
  290. return smart;
  291. }
  292. Evas_Object* ewk_view_tiled_add(Evas* canvas)
  293. {
  294. return evas_object_smart_add(canvas, _ewk_view_tiled_smart_class_new());
  295. }
  296. Ewk_Tile_Unused_Cache* ewk_view_tiled_unused_cache_get(const Evas_Object* ewkView)
  297. {
  298. EWK_VIEW_TYPE_CHECK_OR_RETURN(ewkView, ewkViewTiledName, 0);
  299. Ewk_View_Smart_Data* smartData = ewk_view_smart_data_get(ewkView);
  300. EINA_SAFETY_ON_NULL_RETURN_VAL(smartData, 0);
  301. return ewk_tiled_backing_store_tile_unused_cache_get(smartData->backing_store);
  302. }
  303. void ewk_view_tiled_unused_cache_set(Evas_Object* ewkView, Ewk_Tile_Unused_Cache* cache)
  304. {
  305. EWK_VIEW_TYPE_CHECK_OR_RETURN(ewkView, ewkViewTiledName);
  306. Ewk_View_Smart_Data* smartData = ewk_view_smart_data_get(ewkView);
  307. EINA_SAFETY_ON_NULL_RETURN(smartData);
  308. ewk_tiled_backing_store_tile_unused_cache_set(smartData->backing_store, cache);
  309. }