PassRefPtr<BitmapContext> createBitmapContextFromWebView(bool, bool, bool, bool drawSelectionRect) { Ewk_View_Smart_Data* smartData = static_cast<Ewk_View_Smart_Data*>(evas_object_smart_data_get(browser->mainView())); Ewk_View_Private_Data* privateData = static_cast<Ewk_View_Private_Data*>(smartData->_priv); const Evas_Object* mainFrame = browser->mainFrame(); int x, y, width, height; if (!ewk_frame_visible_content_geometry_get(mainFrame, EINA_TRUE, &x, &y, &width, &height)) return 0; RefPtr<cairo_surface_t> surface = adoptRef(cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height)); RefPtr<cairo_t> context = adoptRef(cairo_create(surface.get())); const Eina_Rectangle rect = { x, y, width, height }; if (!ewk_view_paint(privateData, context.get(), &rect)) return 0; if (DumpRenderTreeSupportEfl::isTrackingRepaints(mainFrame)) { cairo_push_group(context.get()); // Paint the gray mask over the original image. cairo_set_source_rgba(context.get(), 0, 0, 0, 0.66); cairo_paint(context.get()); // Paint transparent rectangles over the mask to show the repainted regions. cairo_set_source_rgba(context.get(), 0, 0, 0, 0); cairo_set_operator(context.get(), CAIRO_OPERATOR_SOURCE); Eina_List* repaintRects = DumpRenderTreeSupportEfl::trackedRepaintRects(mainFrame); void* iter = 0; EINA_LIST_FREE(repaintRects, iter) { Eina_Rectangle* rect = static_cast<Eina_Rectangle*>(iter); cairo_rectangle(context.get(), rect->x, rect->y, rect->w, rect->h); cairo_fill(context.get()); eina_rectangle_free(rect); } cairo_pop_group_to_source(context.get()); cairo_paint(context.get()); }
/* calculates one good zoom level to fit given hit test result */ static float _view_zoom_fits_hit(View_Smart_Data *sd, const Ewk_Hit_Test *hit_test) { Evas_Coord x, y; /* hit test point */ Evas_Coord bx, by, bw, bh, bw1, bw2, bh1, bh2; /* bounding box */ Evas_Coord vx, vy, vw, vh, vw1, vw2, vh1, vh2; /* visible content */ Evas_Coord cw, ch; float zx, zy, z, old_zoom, zx1, zx2, zy1, zy2; if (!hit_test) return 0.0; old_zoom = ewk_frame_page_zoom_get(sd->base.main_frame); /* save some typing */ x = hit_test->x; y = hit_test->y; bx = hit_test->bounding_box.x; by = hit_test->bounding_box.y; bw = hit_test->bounding_box.w; bh = hit_test->bounding_box.h; if ((bw <= 0) || (bh <= 0)) return 0.0; ewk_frame_visible_content_geometry_get (sd->base.main_frame, EINA_FALSE, &vx, &vy, &vw, &vh); if ((vw <= 0) || (vh <= 0)) return 0.0; ewk_frame_contents_size_get(sd->base.main_frame, &cw, &ch); if ((cw <= 0) || (ch <= 0)) return 0.0; /* split width of left and right parts from hit test position */ bw1 = x - bx; bw2 = bw - bw1; /* split height of top and bottom parts from hit test position */ bh1 = y - by; bh2 = bh - bh1; /* split size of viewport as well. We'll use this as the available space */ vw1 = x - vx; vw2 = vw - vw1; vh1 = y - vy; vh2 = vh - vh1; /* check if we can add padding around those sizes, "adding" if possible * (we actually subtract as adding a pad is removing available space) */ if (vw1 > ZOOM_AUTO_PADDING) vw1 -= ZOOM_AUTO_PADDING; if (vw2 > ZOOM_AUTO_PADDING) vw2 -= ZOOM_AUTO_PADDING; if (vh1 > ZOOM_AUTO_PADDING) vh1 -= ZOOM_AUTO_PADDING; if (vh2 > ZOOM_AUTO_PADDING) vh2 -= ZOOM_AUTO_PADDING; /* check individual zoom to fit each part */ zx1 = (bw1 > 0) ? (vw1 / (float)bw1) : 0.0; zx2 = (bw2 > 0) ? (vw2 / (float)bw2) : 0.0; zy1 = (bh1 > 0) ? (vh1 / (float)bh1) : 0.0; zy2 = (bh2 > 0) ? (vh2 / (float)bh2) : 0.0; if ((zx1 >= ZOOM_AUTO_MIN_DIFFERENCE) && (zx2 >= ZOOM_AUTO_MIN_DIFFERENCE)) zx = (zx1 < zx2) ? zx1 : zx2; else if (zx1 >= ZOOM_AUTO_MIN_DIFFERENCE) zx = zx1; else zx = zx2; if ((zy1 >= ZOOM_AUTO_MIN_DIFFERENCE) && (zy2 >= ZOOM_AUTO_MIN_DIFFERENCE)) zy = (zy1 < zy2) ? zy1 : zy2; else if (zy1 >= ZOOM_AUTO_MIN_DIFFERENCE) zy = zy1; else zy = zy2; if ((zx >= ZOOM_AUTO_MIN_DIFFERENCE) && (zy >= ZOOM_AUTO_MIN_DIFFERENCE)) z = (zx < zy) ? zx : zy; else if (zx >= ZOOM_AUTO_MIN_DIFFERENCE) z = zx; else z = zy; /* zoom will make contents be smaller than viewport, limit it */ if (((int)(z * old_zoom * cw) < vw) || ((int)(z * old_zoom * ch) < vh)) { float ac = cw / (float)ch; float av = vw / (float)vh; if (ac < av) z = vw / (float)cw; else z = vh / (float)ch; } #if 0 /* debug */ printf(">>> fit: center=%3d,%3d box=%3d,%3d+%3dx%3d\n" " x: %3d = %3d + %3d, %3d = %3d + %3d, %2.4f %2.4f -> %2.4f\n" " y: %3d = %3d + %3d, %3d = %3d + %3d, %2.4f %2.4f -> %2.4f\n" " final: %2.4f %2.4f (old=%0.3f, difference=%0.3f)\n" " contents: %4dx%4d -> %4dx%4d\n" "\n", x, y, bx, by, bw, bh, bw, bw1, bw2, vw, vw1, vw2, zx1, zx2, zx, bh, bh1, bh2, vh, vh1, vh2, zy1, zy2, zy, z, old_zoom * z, old_zoom, fabs(old_zoom - z), cw, ch, (int)(z * old_zoom * cw), (int)(z * old_zoom * ch)); #endif z *= old_zoom; if (z < ZOOM_AUTO_MIN) z = ZOOM_AUTO_MIN; else if (z > ZOOM_AUTO_MAX) z = ZOOM_AUTO_MAX; if (fabs(old_zoom - z) < ZOOM_AUTO_MIN_DIFFERENCE) return 0.0; return z; }
static Eina_Bool _ewk_view_tiled_smart_pre_render_start(Ewk_View_Smart_Data* smartData) { int contentWidth, contentHeight; ewk_frame_contents_size_get(smartData->main_frame, &contentWidth, &contentHeight); int viewX, viewY, viewWidth, viewHeight; ewk_frame_visible_content_geometry_get(smartData->main_frame, false, &viewX, &viewY, &viewWidth, &viewHeight); if (viewWidth <= 0 || viewHeight <= 0 || contentWidth <= 0 || contentHeight <= 0) return false; if (viewWidth >= contentWidth && viewHeight >= contentHeight) return false; int previousViewX, previousViewY; previousViewX = smartData->previousView.x; previousViewY = smartData->previousView.y; if (previousViewX < 0 || previousViewX > contentWidth || previousViewY < 0 || previousViewY > contentHeight) previousViewX = previousViewY = 0; float currentViewZoom = ewk_view_zoom_get(smartData->self); // pre-render works when two conditions are met. // zoom has been changed. // and the view has been moved more than tile size. if (abs(previousViewX - viewX) < defaultTileWidth && abs(previousViewY - viewY) < defaultTileHeigth && smartData->previousView.zoom == currentViewZoom) { return false; } // store previous view position and zoom. smartData->previousView.x = viewX; smartData->previousView.y = viewY; smartData->previousView.zoom = currentViewZoom; // cancelling previous pre-rendering list if exists. ewk_view_pre_render_cancel(smartData->self); Ewk_Tile_Unused_Cache* tileUnusedCache = ewk_view_tiled_unused_cache_get(smartData->self); int maxMemory = ewk_tile_unused_cache_max_get(tileUnusedCache); if (maxMemory <= viewWidth * viewHeight * EWK_ARGB_BYTES_SIZE) return false; Eina_Rectangle viewRect = {viewX, viewY, viewWidth, viewHeight}; Eina_Rectangle contentRect = {0, 0, contentWidth, contentHeight}; // get a base render rect. const int contentMemory = contentWidth * contentHeight * EWK_ARGB_BYTES_SIZE; // get render rect's width and height. Eina_Rectangle renderRect; if (maxMemory > contentMemory) renderRect = contentRect; else { // Make a base rectangle as big as possible with using maxMemory. // and then reshape the base rectangle to fit to contents. const int baseSize = static_cast<int>(sqrt(maxMemory / 4.0f)); const float widthRate = (viewRect.w + (defaultTileWidth * 2)) / static_cast<float>(baseSize); const float heightRate = baseSize / static_cast<float>(contentHeight); const float rectRate = std::max(widthRate, heightRate); renderRect.w = static_cast<int>(baseSize * rectRate); renderRect.h = static_cast<int>(baseSize / rectRate); renderRect.x = viewRect.x + (viewRect.w / 2) - (renderRect.w / 2); renderRect.y = viewRect.y + (viewRect.h / 2) - (renderRect.h / 2); // reposition of renderRect, if the renderRect overlapped the content rect, this code moves the renderRect inside the content rect. int collisionSide = _ewk_view_tiled_rect_collision_check(renderRect, contentRect); if (collisionSide > 0) _ewk_view_tiled_rect_collision_resolve(collisionSide, &renderRect, contentRect); // check abnormal render rect if (renderRect.x < 0) renderRect.x = 0; if (renderRect.y < 0) renderRect.y = 0; if (renderRect.w > contentWidth) renderRect.w = contentWidth; if (renderRect.h > contentHeight) renderRect.h = contentHeight; } // enqueue tiles into tiled backing store in spiral order. ewk_tiled_backing_store_pre_render_spiral_queue(smartData->backing_store, &viewRect, &renderRect, maxMemory, currentViewZoom); return true; }