123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952 |
- // Copyright 2014 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "android_webview/browser/gfx/browser_view_renderer.h"
- #include <memory>
- #include <utility>
- #include "android_webview/browser/gfx/browser_view_renderer_client.h"
- #include "android_webview/browser/gfx/compositor_frame_consumer.h"
- #include "android_webview/browser/gfx/root_frame_sink.h"
- #include "android_webview/browser/gfx/root_frame_sink_proxy.h"
- #include "android_webview/common/aw_features.h"
- #include "base/auto_reset.h"
- #include "base/check_op.h"
- #include "base/command_line.h"
- #include "base/memory/raw_ptr.h"
- #include "base/numerics/safe_conversions.h"
- #include "base/strings/string_number_conversions.h"
- #include "base/strings/stringprintf.h"
- #include "base/supports_user_data.h"
- #include "base/trace_event/traced_value.h"
- #include "cc/base/math_util.h"
- #include "components/viz/common/features.h"
- #include "components/viz/common/frame_sinks/copy_output_request.h"
- #include "components/viz/common/quads/compositor_frame.h"
- #include "content/public/browser/render_process_host.h"
- #include "content/public/browser/render_view_host.h"
- #include "content/public/browser/web_contents.h"
- #include "content/public/common/content_switches.h"
- #include "gpu/command_buffer/service/gpu_switches.h"
- #include "third_party/skia/include/core/SkBitmap.h"
- #include "third_party/skia/include/core/SkCanvas.h"
- #include "third_party/skia/include/core/SkPicture.h"
- #include "third_party/skia/include/core/SkPictureRecorder.h"
- #include "ui/gfx/geometry/point.h"
- #include "ui/gfx/geometry/point_conversions.h"
- #include "ui/gfx/geometry/point_f.h"
- #include "ui/gfx/geometry/vector2d_conversions.h"
- #include "ui/gfx/geometry/vector2d_f.h"
- namespace android_webview {
- namespace {
- const double kEpsilon = 1e-8;
- // Used to calculate memory allocation. Determined experimentally.
- const size_t kMemoryMultiplier = 20;
- const size_t kBytesPerPixel = 4;
- const size_t kMemoryAllocationStep = 5 * 1024 * 1024;
- uint64_t g_memory_override_in_bytes = 0u;
- const void* const kBrowserViewRendererUserDataKey =
- &kBrowserViewRendererUserDataKey;
- class BrowserViewRendererUserData : public base::SupportsUserData::Data {
- public:
- explicit BrowserViewRendererUserData(BrowserViewRenderer* ptr) : bvr_(ptr) {}
- static BrowserViewRenderer* GetBrowserViewRenderer(
- content::WebContents* web_contents) {
- if (!web_contents)
- return NULL;
- BrowserViewRendererUserData* data =
- static_cast<BrowserViewRendererUserData*>(
- web_contents->GetUserData(kBrowserViewRendererUserDataKey));
- return data ? data->bvr_.get() : NULL;
- }
- private:
- raw_ptr<BrowserViewRenderer> bvr_;
- };
- } // namespace
- // static
- void BrowserViewRenderer::CalculateTileMemoryPolicy() {
- base::CommandLine* cl = base::CommandLine::ForCurrentProcess();
- // If the value was overridden on the command line, use the specified value.
- bool client_hard_limit_bytes_overridden =
- cl->HasSwitch(switches::kForceGpuMemAvailableMb);
- if (client_hard_limit_bytes_overridden) {
- base::StringToUint64(
- base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
- switches::kForceGpuMemAvailableMb),
- &g_memory_override_in_bytes);
- g_memory_override_in_bytes *= 1024 * 1024;
- }
- }
- // static
- BrowserViewRenderer* BrowserViewRenderer::FromWebContents(
- content::WebContents* web_contents) {
- return BrowserViewRendererUserData::GetBrowserViewRenderer(web_contents);
- }
- BrowserViewRenderer::BrowserViewRenderer(
- BrowserViewRendererClient* client,
- const scoped_refptr<base::SingleThreadTaskRunner>& ui_task_runner)
- : client_(client),
- ui_task_runner_(ui_task_runner),
- current_compositor_frame_consumer_(nullptr),
- compositor_(nullptr),
- is_paused_(false),
- view_visible_(false),
- window_visible_(false),
- attached_to_window_(false),
- was_attached_(false),
- hardware_enabled_(false),
- dip_scale_(0.f),
- page_scale_factor_(1.f),
- min_page_scale_factor_(0.f),
- max_page_scale_factor_(0.f),
- on_new_picture_enable_(false),
- clear_view_(false),
- offscreen_pre_raster_(false) {
- begin_frame_source_ = std::make_unique<BeginFrameSourceWebView>();
- root_frame_sink_proxy_ = std::make_unique<RootFrameSinkProxy>(
- ui_task_runner_, this, begin_frame_source_.get());
- UpdateBeginFrameSource();
- }
- BrowserViewRenderer::~BrowserViewRenderer() {
- DCHECK(compositor_map_.empty());
- DCHECK(!current_compositor_frame_consumer_);
- // We need to destroy |root_frame_sink_proxy_| before |begin_frame_source_|;
- root_frame_sink_proxy_.reset();
- }
- base::WeakPtr<CompositorFrameProducer> BrowserViewRenderer::GetWeakPtr() {
- return weak_ptr_factory_.GetWeakPtr();
- }
- void BrowserViewRenderer::SetCurrentCompositorFrameConsumer(
- CompositorFrameConsumer* compositor_frame_consumer) {
- if (compositor_frame_consumer == current_compositor_frame_consumer_) {
- return;
- }
- current_compositor_frame_consumer_ = compositor_frame_consumer;
- if (current_compositor_frame_consumer_) {
- // Previous renderer will evict CompositorFrame, compositor needs to submit
- // next frames with new local surface id.
- if (compositor_)
- compositor_->WasEvicted();
- RootFrameSinkGetter root_sink_getter;
- if (root_frame_sink_proxy_)
- root_sink_getter = root_frame_sink_proxy_->GetRootFrameSinkCallback();
- current_compositor_frame_consumer_->SetCompositorFrameProducer(
- this, std::move(root_sink_getter));
- OnParentDrawDataUpdated(current_compositor_frame_consumer_);
- }
- }
- void BrowserViewRenderer::RegisterWithWebContents(
- content::WebContents* web_contents) {
- web_contents->SetUserData(
- kBrowserViewRendererUserDataKey,
- std::make_unique<BrowserViewRendererUserData>(this));
- }
- void BrowserViewRenderer::TrimMemory() {
- DCHECK(ui_task_runner_->BelongsToCurrentThread());
- TRACE_EVENT0("android_webview", "BrowserViewRenderer::TrimMemory");
- // Trimming memory might destroy HardwareRenderer which will evict
- // CompositorFrame, compositor needs to submit next frames with new local
- // surface id.
- if (compositor_)
- compositor_->WasEvicted();
- // Just set the memory limit to 0 and drop all tiles. This will be reset to
- // normal levels in the next DrawGL call.
- if (!offscreen_pre_raster_)
- ReleaseHardware();
- }
- gfx::Rect BrowserViewRenderer::ComputeTileRectAndUpdateMemoryPolicy() {
- if (!compositor_) {
- return gfx::Rect();
- }
- if (!hardware_enabled_) {
- compositor_->SetMemoryPolicy(0u);
- return gfx::Rect();
- }
- gfx::Transform transform_for_tile_priority =
- external_draw_constraints_.transform;
- gfx::Rect viewport_rect_for_tile_priority_in_view_space;
- gfx::Transform screen_to_view(gfx::Transform::kSkipInitialization);
- if (transform_for_tile_priority.GetInverse(&screen_to_view)) {
- // Convert from screen space to view space.
- viewport_rect_for_tile_priority_in_view_space =
- cc::MathUtil::ProjectEnclosingClippedRect(
- screen_to_view,
- gfx::Rect(external_draw_constraints_.viewport_size));
- }
- viewport_rect_for_tile_priority_in_view_space.Intersect(gfx::Rect(size_));
- size_t bytes_limit = 0u;
- if (g_memory_override_in_bytes) {
- bytes_limit = static_cast<size_t>(g_memory_override_in_bytes);
- } else {
- // Note we are using |last_on_draw_global_visible_rect_| rather than
- // |external_draw_constraints_.viewport_size|. This is to reduce budget
- // for a webview that's much smaller than the surface it's rendering.
- gfx::Rect interest_rect;
- if (offscreen_pre_raster_) {
- interest_rect = gfx::Rect(size_);
- } else {
- // Re-compute screen-space rect for computing tile budget, since tile is
- // rastered in screen space.
- gfx::Rect viewport_rect_for_tile_priority_in_screen_space =
- cc::MathUtil::ProjectEnclosingClippedRect(
- transform_for_tile_priority,
- viewport_rect_for_tile_priority_in_view_space);
- // Intersect by viewport size again, in case axis-aligning operations made
- // the rect bigger than necessary.
- viewport_rect_for_tile_priority_in_screen_space.Intersect(
- gfx::Rect(external_draw_constraints_.viewport_size));
- interest_rect = viewport_rect_for_tile_priority_in_screen_space.IsEmpty()
- ? last_on_draw_global_visible_rect_
- : viewport_rect_for_tile_priority_in_screen_space;
- }
- size_t width = interest_rect.width();
- size_t height = interest_rect.height();
- bytes_limit = kMemoryMultiplier * kBytesPerPixel * width * height;
- // Round up to a multiple of kMemoryAllocationStep.
- bytes_limit =
- (bytes_limit / kMemoryAllocationStep + 1) * kMemoryAllocationStep;
- }
- compositor_->SetMemoryPolicy(bytes_limit);
- return viewport_rect_for_tile_priority_in_view_space;
- }
- content::SynchronousCompositor* BrowserViewRenderer::FindCompositor(
- const viz::FrameSinkId& frame_sink_id) const {
- const auto& compositor_iterator = compositor_map_.find(frame_sink_id);
- if (compositor_iterator == compositor_map_.end())
- return nullptr;
- return compositor_iterator->second;
- }
- void BrowserViewRenderer::PrepareToDraw(const gfx::Point& scroll,
- const gfx::Rect& global_visible_rect) {
- last_on_draw_scroll_offset_ = scroll;
- last_on_draw_global_visible_rect_ = global_visible_rect;
- }
- bool BrowserViewRenderer::CanOnDraw() {
- if (!compositor_) {
- TRACE_EVENT_INSTANT0("android_webview", "EarlyOut_NoCompositor",
- TRACE_EVENT_SCOPE_THREAD);
- return false;
- }
- if (clear_view_) {
- TRACE_EVENT_INSTANT0("android_webview", "EarlyOut_ClearView",
- TRACE_EVENT_SCOPE_THREAD);
- return false;
- }
- return true;
- }
- bool BrowserViewRenderer::OnDrawHardware() {
- DCHECK(current_compositor_frame_consumer_);
- TRACE_EVENT0("android_webview", "BrowserViewRenderer::OnDrawHardware");
- const bool did_invalidate = did_invalidate_since_last_draw_;
- did_invalidate_since_last_draw_ = false;
- if (!CanOnDraw()) {
- return false;
- }
- current_compositor_frame_consumer_->SetScrollOffsetOnUI(
- last_on_draw_scroll_offset_);
- hardware_enabled_ = true;
- DoUpdateParentDrawData();
- // Do not override (ie leave empty) for offscreen raster.
- gfx::Size viewport_size_for_tile_priority =
- offscreen_pre_raster_ ? gfx::Size()
- : external_draw_constraints_.viewport_size;
- gfx::Rect viewport_rect_for_tile_priority_in_view_space =
- ComputeTileRectAndUpdateMemoryPolicy();
- // Explanation for the various viewports and transforms. There are:
- // * "default" viewport" (and identity transform) that's normally used by
- // compositor. This is |size_| in this file.
- // * "draw" viewport and transform. Compositor applies them at the root at
- // draw time. This is contained in SkCanvas for a software draw
- // * "tile" viewport and transform. These are set in hardware draw to
- // correctly prioritize and raster tiles.
- // The draw viewport was added to support software draw's ability to change
- // the viewport and transform at draw time to anything the embedding app
- // desires. However the tile system was not expecting its viewport to jump
- // around, and only move incrementally due to user input. This required adding
- // the tile viewport and transform. Tile and default are separate to reduce
- // memory in the case when only a small portion of webview (ie the default
- // viewport) is actually visible.
- // We intersect the tile viewport with the default viewport above so that the
- // tile viewport can only shrink and not grow from the default viewport. This
- // is because webview can also be small in relation to the surface size, so
- // and growing the tile viewport can cause more tiles to be rastered than
- // necessary.
- scoped_refptr<content::SynchronousCompositor::FrameFuture> future =
- compositor_->DemandDrawHwAsync(
- size_, viewport_rect_for_tile_priority_in_view_space,
- external_draw_constraints_.transform);
- CopyOutputRequestQueue requests;
- copy_requests_.swap(requests);
- for (auto& copy_request_ptr : requests) {
- if (!copy_request_ptr->has_result_task_runner())
- copy_request_ptr->set_result_task_runner(ui_task_runner_);
- }
- std::unique_ptr<ChildFrame> child_frame = std::make_unique<ChildFrame>(
- std::move(future), frame_sink_id_, viewport_size_for_tile_priority,
- external_draw_constraints_.transform, offscreen_pre_raster_, dip_scale_,
- std::move(requests), did_invalidate,
- begin_frame_source_->LastDispatchedBeginFrameArgs());
- ReturnUnusedResource(
- current_compositor_frame_consumer_->SetFrameOnUI(std::move(child_frame)));
- return true;
- }
- void BrowserViewRenderer::OnParentDrawDataUpdated(
- CompositorFrameConsumer* compositor_frame_consumer) {
- DCHECK(compositor_frame_consumer);
- if (compositor_frame_consumer != current_compositor_frame_consumer_)
- return;
- if (!DoUpdateParentDrawData())
- return;
- PostInvalidate(compositor_);
- ComputeTileRectAndUpdateMemoryPolicy();
- }
- bool BrowserViewRenderer::DoUpdateParentDrawData() {
- ParentCompositorDrawConstraints new_constraints;
- viz::FrameTimingDetailsMap new_timing_details;
- viz::FrameSinkId id;
- uint32_t frame_token = 0u;
- current_compositor_frame_consumer_->TakeParentDrawDataOnUI(
- &new_constraints, &id, &new_timing_details, &frame_token);
- content::SynchronousCompositor* compositor = FindCompositor(id);
- if (compositor) {
- compositor->DidPresentCompositorFrames(std::move(new_timing_details),
- frame_token);
- }
- if (external_draw_constraints_ == new_constraints)
- return false;
- external_draw_constraints_ = new_constraints;
- return true;
- }
- void BrowserViewRenderer::OnViewTreeForceDarkStateChanged(
- bool view_tree_force_dark_state) {
- client_->OnViewTreeForceDarkStateChanged(view_tree_force_dark_state);
- }
- void BrowserViewRenderer::ChildSurfaceWasEvicted() {
- if (compositor_)
- compositor_->WasEvicted();
- }
- void BrowserViewRenderer::RemoveCompositorFrameConsumer(
- CompositorFrameConsumer* consumer) {
- ReturnUncommittedFrames(consumer->PassUncommittedFrameOnUI());
- if (current_compositor_frame_consumer_ == consumer)
- SetCurrentCompositorFrameConsumer(nullptr);
- }
- void BrowserViewRenderer::ReturnUncommittedFrames(
- ChildFrameQueue child_frames) {
- for (auto& child_frame : child_frames)
- ReturnUnusedResource(std::move(child_frame));
- }
- void BrowserViewRenderer::ReturnUnusedResource(
- std::unique_ptr<ChildFrame> child_frame) {
- if (!child_frame.get() || !child_frame->frame.get())
- return;
- std::vector<viz::ReturnedResource> resources =
- viz::TransferableResource::ReturnResources(
- child_frame->frame->resource_list);
- content::SynchronousCompositor* compositor =
- FindCompositor(child_frame->frame_sink_id);
- if (compositor && !resources.empty())
- compositor->ReturnResources(child_frame->layer_tree_frame_sink_id,
- std::move(resources));
- }
- void BrowserViewRenderer::ReturnUsedResources(
- std::vector<viz::ReturnedResource> resources,
- const viz::FrameSinkId& frame_sink_id,
- uint32_t layer_tree_frame_sink_id) {
- content::SynchronousCompositor* compositor = FindCompositor(frame_sink_id);
- if (compositor && !resources.empty())
- compositor->ReturnResources(layer_tree_frame_sink_id, std::move(resources));
- has_rendered_frame_ = true;
- }
- bool BrowserViewRenderer::OnDrawSoftware(SkCanvas* canvas) {
- did_invalidate_since_last_draw_ = false;
- return CanOnDraw() && CompositeSW(canvas, /*software_canvas=*/true);
- }
- bool BrowserViewRenderer::NeedToDrawBackgroundColor() {
- return !has_rendered_frame_;
- }
- sk_sp<SkPicture> BrowserViewRenderer::CapturePicture(int width,
- int height) {
- TRACE_EVENT0("android_webview", "BrowserViewRenderer::CapturePicture");
- // Return empty Picture objects for empty SkPictures.
- if (width <= 0 || height <= 0) {
- SkPictureRecorder emptyRecorder;
- emptyRecorder.beginRecording(0, 0);
- return emptyRecorder.finishRecordingAsPicture();
- }
- SkPictureRecorder recorder;
- SkCanvas* rec_canvas = recorder.beginRecording(width, height);
- if (compositor_) {
- {
- // Reset scroll back to the origin, will go back to the old
- // value when scroll_reset is out of scope.
- base::AutoReset<gfx::PointF> scroll_reset(&scroll_offset_unscaled_,
- gfx::PointF());
- compositor_->DidChangeRootLayerScrollOffset(scroll_offset_unscaled_);
- CompositeSW(rec_canvas, /*software_canvas=*/false);
- }
- compositor_->DidChangeRootLayerScrollOffset(scroll_offset_unscaled_);
- }
- return recorder.finishRecordingAsPicture();
- }
- void BrowserViewRenderer::EnableOnNewPicture(bool enabled) {
- on_new_picture_enable_ = enabled;
- }
- void BrowserViewRenderer::ClearView() {
- TRACE_EVENT_INSTANT0("android_webview",
- "BrowserViewRenderer::ClearView",
- TRACE_EVENT_SCOPE_THREAD);
- if (clear_view_)
- return;
- clear_view_ = true;
- // Always invalidate ignoring the compositor to actually clear the webview.
- PostInvalidate(compositor_);
- }
- void BrowserViewRenderer::SetOffscreenPreRaster(bool enable) {
- if (offscreen_pre_raster_ != enable) {
- offscreen_pre_raster_ = enable;
- ComputeTileRectAndUpdateMemoryPolicy();
- }
- }
- void BrowserViewRenderer::SetIsPaused(bool paused) {
- TRACE_EVENT_INSTANT1("android_webview",
- "BrowserViewRenderer::SetIsPaused",
- TRACE_EVENT_SCOPE_THREAD,
- "paused",
- paused);
- is_paused_ = paused;
- UpdateBeginFrameSource();
- }
- void BrowserViewRenderer::SetViewVisibility(bool view_visible) {
- TRACE_EVENT_INSTANT1("android_webview",
- "BrowserViewRenderer::SetViewVisibility",
- TRACE_EVENT_SCOPE_THREAD,
- "view_visible",
- view_visible);
- view_visible_ = view_visible;
- }
- void BrowserViewRenderer::SetWindowVisibility(bool window_visible) {
- TRACE_EVENT_INSTANT1("android_webview",
- "BrowserViewRenderer::SetWindowVisibility",
- TRACE_EVENT_SCOPE_THREAD,
- "window_visible",
- window_visible);
- window_visible_ = window_visible;
- UpdateBeginFrameSource();
- }
- void BrowserViewRenderer::OnSizeChanged(int width, int height) {
- TRACE_EVENT_INSTANT2("android_webview",
- "BrowserViewRenderer::OnSizeChanged",
- TRACE_EVENT_SCOPE_THREAD,
- "width",
- width,
- "height",
- height);
- size_.SetSize(width, height);
- if (offscreen_pre_raster_)
- ComputeTileRectAndUpdateMemoryPolicy();
- }
- void BrowserViewRenderer::OnAttachedToWindow(int width, int height) {
- TRACE_EVENT2("android_webview",
- "BrowserViewRenderer::OnAttachedToWindow",
- "width",
- width,
- "height",
- height);
- attached_to_window_ = true;
- was_attached_ = true;
- size_.SetSize(width, height);
- if (offscreen_pre_raster_)
- ComputeTileRectAndUpdateMemoryPolicy();
- UpdateBeginFrameSource();
- }
- void BrowserViewRenderer::OnDetachedFromWindow() {
- TRACE_EVENT0("android_webview", "BrowserViewRenderer::OnDetachedFromWindow");
- attached_to_window_ = false;
- ReleaseHardware();
- UpdateBeginFrameSource();
- }
- void BrowserViewRenderer::ZoomBy(float delta) {
- if (!compositor_)
- return;
- compositor_->SynchronouslyZoomBy(
- delta, gfx::Point(size_.width() / 2, size_.height() / 2));
- }
- void BrowserViewRenderer::OnComputeScroll(base::TimeTicks animation_time) {
- if (!compositor_)
- return;
- TRACE_EVENT0("android_webview", "BrowserViewRenderer::OnComputeScroll");
- compositor_->OnComputeScroll(animation_time);
- }
- void BrowserViewRenderer::ReleaseHardware() {
- if (current_compositor_frame_consumer_) {
- ReturnUncommittedFrames(
- current_compositor_frame_consumer_->PassUncommittedFrameOnUI());
- }
- hardware_enabled_ = false;
- has_rendered_frame_ = false;
- ComputeTileRectAndUpdateMemoryPolicy();
- }
- bool BrowserViewRenderer::IsVisible() const {
- // Ignore |window_visible_| if |attached_to_window_| is false.
- return view_visible_ && (!attached_to_window_ || window_visible_);
- }
- bool BrowserViewRenderer::IsClientVisible() const {
- // When WebView is not paused, we declare it visible even before it is
- // attached to window to allow for background operations. If it ever gets
- // attached though, the WebView is visible as long as it is attached
- // to a window and the window is visible.
- return is_paused_
- ? false
- : !was_attached_ || (attached_to_window_ && window_visible_);
- }
- void BrowserViewRenderer::UpdateBeginFrameSource() {
- if (IsClientVisible()) {
- begin_frame_source_->SetParentSource(
- RootBeginFrameSourceWebView::GetInstance());
- } else {
- begin_frame_source_->SetParentSource(nullptr);
- }
- }
- gfx::Rect BrowserViewRenderer::GetScreenRect() const {
- return gfx::Rect(client_->GetLocationOnScreen(), size_);
- }
- void BrowserViewRenderer::DidInitializeCompositor(
- content::SynchronousCompositor* compositor,
- const viz::FrameSinkId& frame_sink_id) {
- TRACE_EVENT_INSTANT0("android_webview",
- "BrowserViewRenderer::DidInitializeCompositor",
- TRACE_EVENT_SCOPE_THREAD);
- DCHECK(compositor);
- // This assumes that a RenderViewHost has at most 1 synchronous compositor
- // througout its lifetime.
- DCHECK(compositor_map_.count(frame_sink_id) == 0);
- compositor_map_[frame_sink_id] = compositor;
- if (root_frame_sink_proxy_)
- root_frame_sink_proxy_->AddChildFrameSinkId(frame_sink_id);
- compositor->SetBeginFrameSource(begin_frame_source_.get());
- // At this point, the RVHChanged event for the new RVH that contains the
- // |compositor| might have been fired already, in which case just set the
- // current compositor with the new compositor.
- if (frame_sink_id == frame_sink_id_)
- SetActiveCompositor(compositor);
- }
- void BrowserViewRenderer::DidDestroyCompositor(
- content::SynchronousCompositor* compositor,
- const viz::FrameSinkId& frame_sink_id) {
- TRACE_EVENT_INSTANT0("android_webview",
- "BrowserViewRenderer::DidDestroyCompositor",
- TRACE_EVENT_SCOPE_THREAD);
- DCHECK(compositor_map_.count(frame_sink_id));
- if (compositor_ == compositor) {
- compositor_ = nullptr;
- copy_requests_.clear();
- }
- if (root_frame_sink_proxy_)
- root_frame_sink_proxy_->RemoveChildFrameSinkId(frame_sink_id);
- compositor_map_.erase(frame_sink_id);
- }
- void BrowserViewRenderer::SetActiveFrameSinkId(
- const viz::FrameSinkId& frame_sink_id) {
- frame_sink_id_ = frame_sink_id;
- SetActiveCompositor(FindCompositor(frame_sink_id));
- }
- void BrowserViewRenderer::SetActiveCompositor(
- content::SynchronousCompositor* compositor) {
- if (compositor_ == compositor)
- return;
- if (compositor_)
- compositor_->SetMemoryPolicy(0u);
- compositor_ = compositor;
- copy_requests_.clear();
- if (compositor_) {
- ComputeTileRectAndUpdateMemoryPolicy();
- compositor_->DidBecomeActive();
- }
- }
- void BrowserViewRenderer::SetDipScale(float dip_scale) {
- dip_scale_ = dip_scale;
- CHECK_GT(dip_scale_, 0.f);
- }
- gfx::Point BrowserViewRenderer::max_scroll_offset() const {
- DCHECK_GT(dip_scale_, 0.f);
- return gfx::ToCeiledPoint(
- gfx::ScalePoint(max_scroll_offset_unscaled_, page_scale_factor_));
- }
- void BrowserViewRenderer::ScrollTo(const gfx::Point& scroll_offset) {
- gfx::Point max_offset = max_scroll_offset();
- gfx::PointF scroll_offset_unscaled;
- // To preserve the invariant that scrolling to the maximum physical pixel
- // value also scrolls to the maximum dip pixel value we transform the physical
- // offset into the dip offset by using a proportion (instead of dividing by
- // dip_scale * page_scale_factor).
- if (max_offset.x()) {
- scroll_offset_unscaled.set_x(
- (scroll_offset.x() * max_scroll_offset_unscaled_.x()) / max_offset.x());
- }
- if (max_offset.y()) {
- scroll_offset_unscaled.set_y(
- (scroll_offset.y() * max_scroll_offset_unscaled_.y()) / max_offset.y());
- }
- DCHECK_LE(0.f, scroll_offset_unscaled.x());
- DCHECK_LE(0.f, scroll_offset_unscaled.y());
- DCHECK(scroll_offset_unscaled.x() < max_scroll_offset_unscaled_.x() ||
- scroll_offset_unscaled.x() - max_scroll_offset_unscaled_.x() <
- kEpsilon)
- << scroll_offset_unscaled.x() << " " << max_scroll_offset_unscaled_.x();
- DCHECK(scroll_offset_unscaled.y() < max_scroll_offset_unscaled_.y() ||
- scroll_offset_unscaled.y() - max_scroll_offset_unscaled_.y() <
- kEpsilon)
- << scroll_offset_unscaled.y() << " " << max_scroll_offset_unscaled_.y();
- if (scroll_offset_unscaled_ == scroll_offset_unscaled)
- return;
- scroll_offset_unscaled_ = scroll_offset_unscaled;
- TRACE_EVENT_INSTANT2("android_webview", "BrowserViewRenderer::ScrollTo",
- TRACE_EVENT_SCOPE_THREAD, "x",
- scroll_offset_unscaled.x(), "y",
- scroll_offset_unscaled.y());
- if (compositor_)
- compositor_->DidChangeRootLayerScrollOffset(scroll_offset_unscaled);
- }
- void BrowserViewRenderer::RestoreScrollAfterTransition(
- const gfx::Point& scroll_offset) {
- // Determine if the clipped scroll offset.
- gfx::Point clipped_offset = scroll_offset;
- clipped_offset.SetToMin(max_scroll_offset());
- // If the scroll will be clipped due to the max scroll then we haven't
- // received a ScrollStateUpdate with the revised max scroll values. This
- // situation occurs due to a race in exiting fullscreen mode request, we need
- // to wait for the max scroll values to be updated before applying the
- // restored scroll values.
- if (clipped_offset != scroll_offset) {
- scroll_on_scroll_state_update_ = scroll_offset;
- } else {
- ScrollTo(scroll_offset);
- }
- }
- void BrowserViewRenderer::DidUpdateContent(
- content::SynchronousCompositor* compositor) {
- TRACE_EVENT_INSTANT0("android_webview",
- "BrowserViewRenderer::DidUpdateContent",
- TRACE_EVENT_SCOPE_THREAD);
- if (compositor != compositor_)
- return;
- clear_view_ = false;
- if (on_new_picture_enable_)
- client_->OnNewPicture();
- }
- void BrowserViewRenderer::SetTotalRootLayerScrollOffset(
- const gfx::PointF& scroll_offset_unscaled) {
- if (scroll_offset_unscaled_ == scroll_offset_unscaled)
- return;
- scroll_offset_unscaled_ = scroll_offset_unscaled;
- gfx::Point max_offset = max_scroll_offset();
- gfx::Point scroll_offset;
- // For an explanation as to why this is done this way see the comment in
- // BrowserViewRenderer::ScrollTo.
- if (max_scroll_offset_unscaled_.x()) {
- scroll_offset.set_x(
- base::ClampRound((scroll_offset_unscaled.x() * max_offset.x()) /
- max_scroll_offset_unscaled_.x()));
- }
- if (max_scroll_offset_unscaled_.y()) {
- scroll_offset.set_y(
- base::ClampRound((scroll_offset_unscaled.y() * max_offset.y()) /
- max_scroll_offset_unscaled_.y()));
- }
- DCHECK_LE(0, scroll_offset.x());
- DCHECK_LE(0, scroll_offset.y());
- DCHECK_LE(scroll_offset.x(), max_offset.x());
- DCHECK_LE(scroll_offset.y(), max_offset.y());
- client_->ScrollContainerViewTo(scroll_offset);
- }
- void BrowserViewRenderer::UpdateRootLayerState(
- content::SynchronousCompositor* compositor,
- const gfx::PointF& total_scroll_offset,
- const gfx::PointF& total_max_scroll_offset,
- const gfx::SizeF& scrollable_size,
- float page_scale_factor,
- float min_page_scale_factor,
- float max_page_scale_factor) {
- if (compositor != compositor_)
- return;
- gfx::SizeF scrollable_size_dip = scrollable_size;
- scrollable_size_dip.Scale(1 / dip_scale_);
- TRACE_EVENT_INSTANT1(
- "android_webview", "BrowserViewRenderer::UpdateRootLayerState",
- TRACE_EVENT_SCOPE_THREAD, "state",
- RootLayerStateAsValue(total_scroll_offset, scrollable_size_dip));
- DCHECK_GE(total_max_scroll_offset.x(), 0.f);
- DCHECK_GE(total_max_scroll_offset.y(), 0.f);
- DCHECK_GT(page_scale_factor, 0.f);
- // SetDipScale should have been called at least once before this is called.
- DCHECK_GT(dip_scale_, 0.f);
- bool apply_scroll_to = false;
- if (max_scroll_offset_unscaled_ != total_max_scroll_offset ||
- scrollable_size_dip_ != scrollable_size_dip ||
- page_scale_factor_ != page_scale_factor ||
- min_page_scale_factor_ != min_page_scale_factor ||
- max_page_scale_factor_ != max_page_scale_factor) {
- max_scroll_offset_unscaled_ = total_max_scroll_offset;
- scrollable_size_dip_ = scrollable_size_dip;
- page_scale_factor_ = page_scale_factor;
- min_page_scale_factor_ = min_page_scale_factor;
- max_page_scale_factor_ = max_page_scale_factor;
- client_->UpdateScrollState(max_scroll_offset(), scrollable_size_dip,
- page_scale_factor, min_page_scale_factor,
- max_page_scale_factor);
- apply_scroll_to = scroll_on_scroll_state_update_.has_value();
- }
- SetTotalRootLayerScrollOffset(total_scroll_offset);
- if (apply_scroll_to) {
- ScrollTo(scroll_on_scroll_state_update_.value());
- scroll_on_scroll_state_update_.reset();
- }
- }
- std::unique_ptr<base::trace_event::ConvertableToTraceFormat>
- BrowserViewRenderer::RootLayerStateAsValue(
- const gfx::PointF& total_scroll_offset,
- const gfx::SizeF& scrollable_size_dip) {
- std::unique_ptr<base::trace_event::TracedValue> state(
- new base::trace_event::TracedValue());
- state->SetDouble("total_scroll_offset.x", total_scroll_offset.x());
- state->SetDouble("total_scroll_offset.y", total_scroll_offset.y());
- state->SetDouble("max_scroll_offset_unscaled.x",
- max_scroll_offset_unscaled_.x());
- state->SetDouble("max_scroll_offset_unscaled.y",
- max_scroll_offset_unscaled_.y());
- state->SetDouble("scrollable_size_dip.width", scrollable_size_dip.width());
- state->SetDouble("scrollable_size_dip.height", scrollable_size_dip.height());
- state->SetDouble("page_scale_factor", page_scale_factor_);
- return std::move(state);
- }
- void BrowserViewRenderer::DidOverscroll(
- content::SynchronousCompositor* compositor,
- const gfx::Vector2dF& accumulated_overscroll,
- const gfx::Vector2dF& latest_overscroll_delta,
- const gfx::Vector2dF& current_fling_velocity) {
- if (compositor != compositor_)
- return;
- const float physical_pixel_scale = dip_scale_ * page_scale_factor_;
- if (accumulated_overscroll == latest_overscroll_delta)
- overscroll_rounding_error_ = gfx::Vector2dF();
- gfx::Vector2dF scaled_overscroll_delta =
- gfx::ScaleVector2d(latest_overscroll_delta, physical_pixel_scale);
- gfx::Vector2d rounded_overscroll_delta = gfx::ToRoundedVector2d(
- scaled_overscroll_delta + overscroll_rounding_error_);
- overscroll_rounding_error_ =
- scaled_overscroll_delta - rounded_overscroll_delta;
- gfx::Vector2dF fling_velocity_pixels =
- gfx::ScaleVector2d(current_fling_velocity, physical_pixel_scale);
- client_->DidOverscroll(rounded_overscroll_delta, fling_velocity_pixels,
- begin_frame_source_->inside_begin_frame());
- }
- ui::TouchHandleDrawable* BrowserViewRenderer::CreateDrawable() {
- return client_->CreateDrawable();
- }
- void BrowserViewRenderer::CopyOutput(
- content::SynchronousCompositor* compositor,
- std::unique_ptr<viz::CopyOutputRequest> copy_request) {
- if (compositor != compositor_ || !hardware_enabled_)
- return;
- copy_requests_.emplace_back(std::move(copy_request));
- PostInvalidate(compositor_);
- }
- void BrowserViewRenderer::Invalidate() {
- if (compositor_)
- compositor_->DidInvalidate();
- PostInvalidate(compositor_);
- }
- void BrowserViewRenderer::ReturnResourcesFromViz(
- viz::FrameSinkId frame_sink_id,
- uint32_t layer_tree_frame_sink_id,
- std::vector<viz::ReturnedResource> resources) {
- ReturnUsedResources(std::move(resources), frame_sink_id,
- layer_tree_frame_sink_id);
- }
- void BrowserViewRenderer::OnCompositorFrameTransitionDirectiveProcessed(
- viz::FrameSinkId frame_sink_id,
- uint32_t layer_tree_frame_sink_id,
- uint32_t sequence_id) {
- content::SynchronousCompositor* compositor = FindCompositor(frame_sink_id);
- if (compositor) {
- compositor->OnCompositorFrameTransitionDirectiveProcessed(
- layer_tree_frame_sink_id, sequence_id);
- }
- }
- void BrowserViewRenderer::OnInputEvent() {
- if (root_frame_sink_proxy_)
- root_frame_sink_proxy_->OnInputEvent();
- }
- void BrowserViewRenderer::AddBeginFrameCompletionCallback(
- base::OnceClosure callback) {
- begin_frame_source_->AddBeginFrameCompletionCallback(std::move(callback));
- }
- void BrowserViewRenderer::PostInvalidate(
- content::SynchronousCompositor* compositor) {
- TRACE_EVENT_INSTANT0("android_webview", "BrowserViewRenderer::PostInvalidate",
- TRACE_EVENT_SCOPE_THREAD);
- if (compositor != compositor_)
- return;
- did_invalidate_since_last_draw_ = true;
- client_->PostInvalidate(
- RootBeginFrameSourceWebView::GetInstance()->inside_begin_frame());
- }
- bool BrowserViewRenderer::CompositeSW(SkCanvas* canvas, bool software_canvas) {
- DCHECK(compositor_);
- return compositor_->DemandDrawSw(canvas, software_canvas);
- }
- std::string BrowserViewRenderer::ToString() const {
- std::string str;
- base::StringAppendF(&str, "is_paused: %d ", is_paused_);
- base::StringAppendF(&str, "view_visible: %d ", view_visible_);
- base::StringAppendF(&str, "window_visible: %d ", window_visible_);
- base::StringAppendF(&str, "dip_scale: %f ", dip_scale_);
- base::StringAppendF(&str, "page_scale_factor: %f ", page_scale_factor_);
- base::StringAppendF(&str, "view size: %s ", size_.ToString().c_str());
- base::StringAppendF(&str, "attached_to_window: %d ", attached_to_window_);
- base::StringAppendF(&str,
- "global visible rect: %s ",
- last_on_draw_global_visible_rect_.ToString().c_str());
- base::StringAppendF(&str, "scroll_offset_unscaled: %s ",
- scroll_offset_unscaled_.ToString().c_str());
- base::StringAppendF(&str,
- "overscroll_rounding_error_: %s ",
- overscroll_rounding_error_.ToString().c_str());
- base::StringAppendF(
- &str, "on_new_picture_enable: %d ", on_new_picture_enable_);
- base::StringAppendF(&str, "clear_view: %d ", clear_view_);
- return str;
- }
- } // namespace android_webview
|