Commit message: None
CVE: CVE-2017-5094
CWE: CWE-704
Vulnerability description: Type confusion in extensions JavaScript bindings in Google Chrome prior to 60.0.3112.78 for Mac, Windows, Linux, and Android allowed a remote attacker to potentially maliciously modify objects via a crafted HTML page.

Project: Chrome

void SkiaOutputSurfaceImpl::AddContextLostObserver(
    ContextLostObserver* observer) {
  observers_.AddObserver(observer);
}

Project: Chrome

void SkiaOutputSurfaceImpl::ApplyExternalStencil() {
  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
}

Project: Chrome

SkCanvas* SkiaOutputSurfaceImpl::BeginPaintCurrentFrame() {
  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
  DCHECK(!current_paint_);

  if (initialize_waitable_event_) {
    initialize_waitable_event_->Wait();
    initialize_waitable_event_ = nullptr;

    RecreateRootRecorder();
  }

  DCHECK(root_recorder_);

  current_paint_.emplace(&root_recorder_.value());

  if (!renderer_settings_.show_overdraw_feedback)
    return current_paint_->recorder()->getCanvas();

  DCHECK(!overdraw_surface_recorder_);
  DCHECK(renderer_settings_.show_overdraw_feedback);

  SkSurfaceCharacterization characterization = CreateSkSurfaceCharacterization(
      gfx::Size(characterization_.width(), characterization_.height()),
      BGRA_8888, false /* mipmap */, characterization_.refColorSpace());
  overdraw_surface_recorder_.emplace(characterization);
  overdraw_canvas_.emplace((overdraw_surface_recorder_->getCanvas()));

  nway_canvas_.emplace(characterization_.width(), characterization_.height());
  nway_canvas_->addCanvas(current_paint_->recorder()->getCanvas());
  nway_canvas_->addCanvas(&overdraw_canvas_.value());
  return &nway_canvas_.value();
}

Project: Chrome

SkCanvas* SkiaOutputSurfaceImpl::BeginPaintRenderPass(
    const RenderPassId& id,
    const gfx::Size& surface_size,
    ResourceFormat format,
    bool mipmap,
    sk_sp<SkColorSpace> color_space) {
  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
  DCHECK(!current_paint_);
  DCHECK(resource_sync_tokens_.empty());

  SkSurfaceCharacterization c = CreateSkSurfaceCharacterization(
      surface_size, format, mipmap, std::move(color_space));
  current_paint_.emplace(c, id);
  return current_paint_->recorder()->getCanvas();
}

Project: Chrome

void SkiaOutputSurfaceImpl::BindFramebuffer() {
}

Project: Chrome

void SkiaOutputSurfaceImpl::BindToClient(OutputSurfaceClient* client) {
  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
  DCHECK(client);
  DCHECK(!client_);
  client_ = client;
}

Project: Chrome

void SkiaOutputSurfaceImpl::BufferPresented(
    const gfx::PresentationFeedback& feedback) {
  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
  DCHECK(client_);
  client_->DidReceivePresentationFeedback(feedback);
  if (update_vsync_parameters_callback_ &&
      feedback.flags & gfx::PresentationFeedback::kVSync) {
    update_vsync_parameters_callback_.Run(
        feedback.timestamp, feedback.interval.is_zero()
                                ? BeginFrameArgs::DefaultInterval()
                                : feedback.interval);
  }
}

Project: Chrome

void SkiaOutputSurfaceImpl::ContextLost() {
  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
  for (auto& observer : observers_)
    observer.OnContextLost();
}

Project: Chrome

void SkiaOutputSurfaceImpl::CopyOutput(
    RenderPassId id,
    const copy_output::RenderPassGeometry& geometry,
    const gfx::ColorSpace& color_space,
    std::unique_ptr<CopyOutputRequest> request) {
  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
  if (!request->has_result_task_runner())
    request->set_result_task_runner(base::ThreadTaskRunnerHandle::Get());

  auto callback = base::BindOnce(&SkiaOutputSurfaceImplOnGpu::CopyOutput,
                                 base::Unretained(impl_on_gpu_.get()), id,
                                 geometry, color_space, std::move(request),
                                 std::move(deferred_framebuffer_draw_closure_));
  ScheduleGpuTask(std::move(callback), std::move(resource_sync_tokens_));
}

Project: Chrome

SkiaOutputSurfaceImpl::CreateImageContext(
    const gpu::MailboxHolder& holder,
    const gfx::Size& size,
    ResourceFormat format,
    const base::Optional<gpu::VulkanYCbCrInfo>& ycbcr_info,
    sk_sp<SkColorSpace> color_space) {
  return std::make_unique<ImageContextImpl>(holder, size, format, ycbcr_info,
                                            std::move(color_space));
}

Project: Chrome

base::RepeatingCallback<void(Args...)> CreateSafeCallback(
    SkiaOutputSurfaceDependency* dependency,
    const base::RepeatingCallback<void(Args...)>& callback) {
  DCHECK(dependency);
  return base::BindRepeating(&PostAsyncTask<Args...>, dependency, callback);
}

Project: Chrome

SkiaOutputSurfaceImpl::CreateSkSurfaceCharacterization(
    const gfx::Size& surface_size,
    ResourceFormat format,
    bool mipmap,
    sk_sp<SkColorSpace> color_space) {
  auto gr_context_thread_safe = impl_on_gpu_->GetGrContextThreadSafeProxy();
  auto cache_max_resource_bytes = impl_on_gpu_->max_resource_cache_bytes();
  SkSurfaceProps surface_props(0 /*flags */,
                               SkSurfaceProps::kLegacyFontHost_InitType);
  auto color_type =
      ResourceFormatToClosestSkColorType(true /* gpu_compositing */, format);
  auto image_info =
      SkImageInfo::Make(surface_size.width(), surface_size.height(), color_type,
                        kPremul_SkAlphaType, std::move(color_space));
  auto backend_format = gr_context_thread_safe->defaultBackendFormat(
      color_type, GrRenderable::kYes);
  DCHECK(backend_format.isValid());
  auto characterization = gr_context_thread_safe->createCharacterization(
      cache_max_resource_bytes, image_info, backend_format, 0 /* sampleCount */,
      kTopLeft_GrSurfaceOrigin, surface_props, mipmap);
  DCHECK(characterization.isValid());
  return characterization;
}

Project: Chrome

void SkiaOutputSurfaceImpl::DidSwapBuffersComplete(
    gpu::SwapBuffersCompleteParams params,
    const gfx::Size& pixel_size) {
  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
  DCHECK(client_);

  if (!params.texture_in_use_responses.empty())
    client_->DidReceiveTextureInUseResponses(params.texture_in_use_responses);
  if (!params.ca_layer_params.is_empty)
    client_->DidReceiveCALayerParams(params.ca_layer_params);
  client_->DidReceiveSwapBuffersAck(params.swap_response.timings);
  if (needs_swap_size_notifications_)
    client_->DidSwapWithSize(pixel_size);
}

Project: Chrome

void SkiaOutputSurfaceImpl::DiscardBackbuffer() {
  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
  auto callback = base::BindOnce(&SkiaOutputSurfaceImplOnGpu::DiscardBackbuffer,
                                 base::Unretained(impl_on_gpu_.get()));
  task_sequence_->ScheduleOrRetainTask(std::move(callback),
                                       std::vector<gpu::SyncToken>());
}

Project: Chrome

void DoNothing(void* texture_context) {}

Project: Chrome

void SkiaOutputSurfaceImpl::EnsureBackbuffer() {
  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
  auto callback = base::BindOnce(&SkiaOutputSurfaceImplOnGpu::EnsureBackbuffer,
                                 base::Unretained(impl_on_gpu_.get()));
  task_sequence_->ScheduleOrRetainTask(std::move(callback),
                                       std::vector<gpu::SyncToken>());
}

Project: Chrome

sk_sp<SkPromiseImageTexture> Fulfill(void* texture_context) {
  DCHECK(texture_context);
  auto* image_context = static_cast<ImageContextImpl*>(texture_context);
  return sk_ref_sp(image_context->promise_image_texture());
}

Project: Chrome

base::ScopedClosureRunner SkiaOutputSurfaceImpl::GetCacheBackBufferCb() {
  CHECK(false);
  return base::ScopedClosureRunner();
}

Project: Chrome

uint32_t SkiaOutputSurfaceImpl::GetFramebufferCopyTextureFormat() {
  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);

  return GL_RGB;
}

Project: Chrome

gfx::BufferFormat SkiaOutputSurfaceImpl::GetOverlayBufferFormat() const {
  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
  return gfx::BufferFormat::RGBX_8888;
}

Project: Chrome

unsigned SkiaOutputSurfaceImpl::GetOverlayTextureId() const {
  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
  return 0;
}

Project: Chrome

gpu::SurfaceHandle SkiaOutputSurfaceImpl::GetSurfaceHandle() const {
  return dependency_->GetSurfaceHandle();
}

Project: Chrome

bool SkiaOutputSurfaceImpl::Initialize() {
  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);

  task_sequence_ = dependency_->CreateSequence();

  weak_ptr_ = weak_ptr_factory_.GetWeakPtr();
  base::WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL,
                            base::WaitableEvent::InitialState::NOT_SIGNALED);
  bool result = false;
  auto callback = base::BindOnce(&SkiaOutputSurfaceImpl::InitializeOnGpuThread,
                                 base::Unretained(this), &event, &result);
  ScheduleGpuTask(std::move(callback), std::vector<gpu::SyncToken>());
  event.Wait();
  return result;
}

Project: Chrome

bool SkiaOutputSurfaceImpl::IsDisplayedAsOverlayPlane() const {
  return is_displayed_as_overlay_;
}

Project: Chrome

void SkiaOutputSurfaceImpl::MakePromiseSkImage(ImageContext* image_context) {
  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
  DCHECK(current_paint_);
  DCHECK(!image_context->mailbox_holder().mailbox.IsZero());

  images_in_current_paint_.push_back(
      static_cast<ImageContextImpl*>(image_context));

  if (image_context->has_image())
    return;

  SkColorType color_type = ResourceFormatToClosestSkColorType(
      true /* gpu_compositing */, image_context->resource_format());
  GrBackendFormat backend_format = GetGrBackendFormatForTexture(
      image_context->resource_format(),
      image_context->mailbox_holder().texture_target,
      image_context->ycbcr_info());
  image_context->SetImage(
      current_paint_->recorder()->makePromiseTexture(
          backend_format, image_context->size().width(),
          image_context->size().height(), GrMipMapped::kNo,
          image_context->origin(), color_type, image_context->alpha_type(),
          image_context->color_space(), Fulfill /* fulfillProc */,
          DoNothing /* releaseProc */, DoNothing /* doneProc */,
          image_context /* context */),
      backend_format);

  if (image_context->mailbox_holder().sync_token.HasData()) {
    resource_sync_tokens_.push_back(image_context->mailbox_holder().sync_token);
    image_context->mutable_mailbox_holder()->sync_token.Clear();
  }
}

Project: Chrome

sk_sp<SkImage> SkiaOutputSurfaceImpl::MakePromiseSkImageFromRenderPass(
    const RenderPassId& id,
    const gfx::Size& size,
    ResourceFormat format,
    bool mipmap,
    sk_sp<SkColorSpace> color_space) {
  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
  DCHECK(current_paint_);

  auto& image_context = render_pass_image_cache_[id];
  if (!image_context) {
    image_context = std::make_unique<ImageContextImpl>(id, size, format, mipmap,
                                                       std::move(color_space));
  }
  if (!image_context->has_image()) {
    SkColorType color_type =
        ResourceFormatToClosestSkColorType(true /* gpu_compositing */, format);
    GrBackendFormat backend_format = GetGrBackendFormatForTexture(
        format, GL_TEXTURE_2D, /*ycbcr_info=*/base::nullopt);
    image_context->SetImage(
        current_paint_->recorder()->makePromiseTexture(
            backend_format, image_context->size().width(),
            image_context->size().height(), image_context->mipmap(),
            image_context->origin(), color_type, image_context->alpha_type(),
            image_context->color_space(), Fulfill, DoNothing, DoNothing,
            image_context.get()),
        backend_format);
    DCHECK(image_context->has_image());
  }
  images_in_current_paint_.push_back(image_context.get());
  return image_context->image();
}

Project: Chrome

sk_sp<SkImage> SkiaOutputSurfaceImpl::MakePromiseSkImageFromYUV(
    const std::vector<ImageContext*>& contexts,
    SkYUVColorSpace yuv_color_space,
    sk_sp<SkColorSpace> dst_color_space,
    bool has_alpha) {
  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
  DCHECK(current_paint_);
  DCHECK((has_alpha && (contexts.size() == 3 || contexts.size() == 4)) ||
         (!has_alpha && (contexts.size() == 2 || contexts.size() == 3)));

  SkYUVAIndex indices[4];
  PrepareYUVATextureIndices(contexts, has_alpha, indices);

  GrBackendFormat formats[4] = {};
  SkISize yuva_sizes[4] = {};
  SkDeferredDisplayListRecorder::PromiseImageTextureContext
      texture_contexts[4] = {};
  for (size_t i = 0; i < contexts.size(); ++i) {
    auto* context = static_cast<ImageContextImpl*>(contexts[i]);
    DCHECK(context->origin() == kTopLeft_GrSurfaceOrigin);
    formats[i] = GetGrBackendFormatForTexture(
        context->resource_format(), context->mailbox_holder().texture_target,
        /*ycbcr_info=*/base::nullopt);
    yuva_sizes[i].set(context->size().width(), context->size().height());

    context->SetImage(nullptr, formats[i]);

    if (context->mailbox_holder().sync_token.HasData()) {
      resource_sync_tokens_.push_back(context->mailbox_holder().sync_token);
      context->mutable_mailbox_holder()->sync_token.Clear();
    }
    images_in_current_paint_.push_back(context);
    texture_contexts[i] = context;
  }

  auto image = current_paint_->recorder()->makeYUVAPromiseTexture(
      yuv_color_space, formats, yuva_sizes, indices, yuva_sizes[0].width(),
      yuva_sizes[0].height(), kTopLeft_GrSurfaceOrigin, dst_color_space,
      Fulfill, DoNothing, DoNothing, texture_contexts);
  DCHECK(image);
  return image;
}

Project: Chrome

void SkiaOutputSurfaceImpl::OnGpuVSync(base::TimeTicks timebase,
                                       base::TimeDelta interval) {
  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
  if (gpu_vsync_callback_)
    gpu_vsync_callback_.Run(timebase, interval);
}

Project: Chrome

void PostAsyncTask(SkiaOutputSurfaceDependency* dependency,
                   const base::RepeatingCallback<void(Args...)>& callback,
                   Args... args) {
  dependency->PostTaskToClientThread(base::BindOnce(callback, args...));
}

Project: Chrome

void SkiaOutputSurfaceImpl::PrepareYUVATextureIndices(
    const std::vector<ImageContext*>& contexts,
    bool has_alpha,
    SkYUVAIndex indices[4]) {
  DCHECK((has_alpha && (contexts.size() == 3 || contexts.size() == 4)) ||
         (!has_alpha && (contexts.size() == 2 || contexts.size() == 3)));

  bool uv_interleaved = has_alpha ? contexts.size() == 3 : contexts.size() == 2;

  indices[SkYUVAIndex::kY_Index].fIndex = 0;
  indices[SkYUVAIndex::kY_Index].fChannel = SkColorChannel::kR;

  if (uv_interleaved) {
    indices[SkYUVAIndex::kU_Index].fIndex = 1;
    indices[SkYUVAIndex::kU_Index].fChannel = SkColorChannel::kR;

    indices[SkYUVAIndex::kV_Index].fIndex = 1;
    indices[SkYUVAIndex::kV_Index].fChannel = SkColorChannel::kG;

    indices[SkYUVAIndex::kA_Index].fIndex = has_alpha ? 2 : -1;
    indices[SkYUVAIndex::kA_Index].fChannel = SkColorChannel::kR;
  } else {
    indices[SkYUVAIndex::kU_Index].fIndex = 1;
    indices[SkYUVAIndex::kU_Index].fChannel = SkColorChannel::kR;

    indices[SkYUVAIndex::kV_Index].fIndex = 2;
    indices[SkYUVAIndex::kV_Index].fChannel = SkColorChannel::kR;

    indices[SkYUVAIndex::kA_Index].fIndex = has_alpha ? 3 : -1;
    indices[SkYUVAIndex::kA_Index].fChannel = SkColorChannel::kR;
  }
}

Project: Chrome

void SkiaOutputSurfaceImpl::RecreateRootRecorder() {
  DCHECK(characterization_.isValid());
  root_recorder_.emplace(characterization_);

  ignore_result(root_recorder_->getCanvas());
}

Project: Chrome

void SkiaOutputSurfaceImpl::RemoveContextLostObserver(
    ContextLostObserver* observer) {
  observers_.RemoveObserver(observer);
}

Project: Chrome

void SkiaOutputSurfaceImpl::RemoveRenderPassResource(
    std::vector<RenderPassId> ids) {
  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
  DCHECK(!ids.empty());

  std::vector<std::unique_ptr<ImageContextImpl>> image_contexts;
  image_contexts.reserve(ids.size());
  for (const auto id : ids) {
    auto it = render_pass_image_cache_.find(id);
    if (it != render_pass_image_cache_.end()) {
      it->second->clear_image();
      image_contexts.push_back(std::move(it->second));
      render_pass_image_cache_.erase(it);
    }
  }

  if (!image_contexts.empty()) {
    auto callback = base::BindOnce(
        &SkiaOutputSurfaceImplOnGpu::RemoveRenderPassResource,
        base::Unretained(impl_on_gpu_.get()), std::move(image_contexts));
    ScheduleGpuTask(std::move(callback), std::vector<gpu::SyncToken>());
  }
}

Project: Chrome

void SkiaOutputSurfaceImpl::ScheduleDCLayers(
    std::vector<DCLayerOverlay> overlays) {
  auto task =
      base::BindOnce(&SkiaOutputSurfaceImplOnGpu::ScheduleDCLayers,
                     base::Unretained(impl_on_gpu_.get()), std::move(overlays));
  ScheduleGpuTask(std::move(task), {});
}

Project: Chrome

void SkiaOutputSurfaceImpl::ScheduleGpuTask(
    base::OnceClosure callback,
    std::vector<gpu::SyncToken> sync_tokens) {
  task_sequence_->ScheduleTask(std::move(callback), std::move(sync_tokens));
}

Project: Chrome

void SkiaOutputSurfaceImpl::ScheduleGpuTaskForTesting(
    base::OnceClosure callback,
    std::vector<gpu::SyncToken> sync_tokens) {
  ScheduleGpuTask(std::move(callback), std::move(sync_tokens));
}

Project: Chrome

void SkiaOutputSurfaceImpl::ScheduleOutputSurfaceAsOverlay(
    OverlayProcessor::OutputSurfaceOverlayPlane output_surface_plane) {
  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
  auto callback = base::BindOnce(
      &SkiaOutputSurfaceImplOnGpu::ScheduleOutputSurfaceAsOverlay,
      base::Unretained(impl_on_gpu_.get()), std::move(output_surface_plane));
  ScheduleGpuTask(std::move(callback), std::vector<gpu::SyncToken>());
}

Project: Chrome

SkiaOutputSurfaceImpl::ScopedPaint::ScopedPaint(
    SkDeferredDisplayListRecorder* root_recorder)
    : recorder_(root_recorder), render_pass_id_(0) {}

Project: Chrome

SkiaOutputSurfaceImpl::ScopedPaint::ScopedPaint(
    SkSurfaceCharacterization characterization,
    RenderPassId render_pass_id)
    : render_pass_id_(render_pass_id) {
  recorder_storage_.emplace(characterization);
  recorder_ = &recorder_storage_.value();
}

Project: Chrome

void SkiaOutputSurfaceImpl::SetCapabilitiesForTesting(
    bool flipped_output_surface) {
  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
  DCHECK(impl_on_gpu_);
  capabilities_.flipped_output_surface = flipped_output_surface;
  auto callback =
      base::BindOnce(&SkiaOutputSurfaceImplOnGpu::SetCapabilitiesForTesting,
                     base::Unretained(impl_on_gpu_.get()), capabilities_);
  ScheduleGpuTask(std::move(callback), std::vector<gpu::SyncToken>());
}

Project: Chrome

void SkiaOutputSurfaceImpl::SetDisplayTransformHint(
    gfx::OverlayTransform transform) {
  if (capabilities_.supports_pre_transform)
    pre_transform_ = transform;
}

Project: Chrome

void SkiaOutputSurfaceImpl::SetDrawRectangle(const gfx::Rect& draw_rectangle) {
  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
  DCHECK(capabilities().supports_dc_layers);
  DCHECK(!draw_rectangle_);
  draw_rectangle_.emplace(draw_rectangle);
}

Project: Chrome

void SkiaOutputSurfaceImpl::SetEnableDCLayers(bool enable) {
  auto task = base::BindOnce(&SkiaOutputSurfaceImplOnGpu::SetEnableDCLayers,
                             base::Unretained(impl_on_gpu_.get()), enable);
  ScheduleGpuTask(std::move(task), {});
}

Project: Chrome

void SkiaOutputSurfaceImpl::SetGpuVSyncEnabled(bool enabled) {
  auto task = base::BindOnce(&SkiaOutputSurfaceImplOnGpu::SetGpuVSyncEnabled,
                             base::Unretained(impl_on_gpu_.get()), enabled);
  task_sequence_->ScheduleOrRetainTask(std::move(task), {});
}

Project: Chrome

void SkiaOutputSurfaceImpl::SetNeedsSwapSizeNotifications(
    bool needs_swap_size_notifications) {
  needs_swap_size_notifications_ = needs_swap_size_notifications;
}

Project: Chrome

 void SkiaOutputSurfaceImpl::SetUpdateVSyncParametersCallback(
    UpdateVSyncParametersCallback callback) {
  update_vsync_parameters_callback_ = std::move(callback);
}

Project: Chrome

SkiaOutputSurfaceImpl::SkiaOutputSurfaceImpl(
    util::PassKey<SkiaOutputSurfaceImpl> /* pass_key */,
    std::unique_ptr<SkiaOutputSurfaceDependency> deps,
    const RendererSettings& renderer_settings)
    : dependency_(std::move(deps)),
      is_using_vulkan_(dependency_->IsUsingVulkan()),
      renderer_settings_(renderer_settings) {
  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
}

Project: Chrome

gpu::SyncToken SkiaOutputSurfaceImpl::SkiaSwapBuffers(OutputSurfaceFrame frame,
                                                      bool wants_sync_token) {
  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
  DCHECK(!current_paint_);

  gpu::SyncToken sync_token;
  if (wants_sync_token) {
    sync_token = gpu::SyncToken(
        gpu::CommandBufferNamespace::VIZ_SKIA_OUTPUT_SURFACE,
        impl_on_gpu_->command_buffer_id(), ++sync_fence_release_);
    sync_token.SetVerifyFlush();
  }

  auto callback =
      base::BindOnce(&SkiaOutputSurfaceImplOnGpu::SwapBuffers,
                     base::Unretained(impl_on_gpu_.get()), std::move(frame),
                     std::move(deferred_framebuffer_draw_closure_),
                     sync_token.release_count());
  ScheduleGpuTask(std::move(callback), std::move(resource_sync_tokens_));

  RecreateRootRecorder();

  return sync_token;
}

Project: Chrome

gpu::SyncToken SkiaOutputSurfaceImpl::SubmitPaint(
    base::OnceClosure on_finished) {
  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
  DCHECK(current_paint_);
  DCHECK(!deferred_framebuffer_draw_closure_);

  bool painting_render_pass = current_paint_->render_pass_id() != 0;

  gpu::SyncToken sync_token(
      gpu::CommandBufferNamespace::VIZ_SKIA_OUTPUT_SURFACE,
      impl_on_gpu_->command_buffer_id(), ++sync_fence_release_);
  sync_token.SetVerifyFlush();

  auto ddl = current_paint_->recorder()->detach();
  DCHECK(ddl);
  std::unique_ptr<SkDeferredDisplayList> overdraw_ddl;
  if (renderer_settings_.show_overdraw_feedback && !painting_render_pass) {
    overdraw_ddl = overdraw_surface_recorder_->detach();
    DCHECK(overdraw_ddl);
    overdraw_canvas_.reset();
    nway_canvas_.reset();
    overdraw_surface_recorder_.reset();
  }

  if (painting_render_pass) {
    auto it = render_pass_image_cache_.find(current_paint_->render_pass_id());
    if (it != render_pass_image_cache_.end()) {
      it->second->clear_image();
    }
    DCHECK(!on_finished);
    auto closure = base::BindOnce(
        &SkiaOutputSurfaceImplOnGpu::FinishPaintRenderPass,
        base::Unretained(impl_on_gpu_.get()), current_paint_->render_pass_id(),
        std::move(ddl), std::move(images_in_current_paint_),
        resource_sync_tokens_, sync_fence_release_);
    ScheduleGpuTask(std::move(closure), std::move(resource_sync_tokens_));
  } else {
    deferred_framebuffer_draw_closure_ = base::BindOnce(
        &SkiaOutputSurfaceImplOnGpu::FinishPaintCurrentFrame,
        base::Unretained(impl_on_gpu_.get()), std::move(ddl),
        std::move(overdraw_ddl), std::move(images_in_current_paint_),
        resource_sync_tokens_, sync_fence_release_, std::move(on_finished),
        draw_rectangle_);
    draw_rectangle_.reset();
  }
  images_in_current_paint_.clear();
  current_paint_.reset();
  return sync_token;
}

Project: Chrome

unsigned SkiaOutputSurfaceImpl::UpdateGpuFence() {
  return 0;
}

Project: Chrome

SkiaOutputSurfaceImpl::~SkiaOutputSurfaceImpl() {
  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
  current_paint_.reset();
  root_recorder_.reset();

  std::vector<std::unique_ptr<ImageContextImpl>> render_pass_image_contexts;
  render_pass_image_contexts.reserve(render_pass_image_cache_.size());
  for (auto& id_and_image_context : render_pass_image_cache_) {
    id_and_image_context.second->clear_image();
    render_pass_image_contexts.push_back(
        std::move(id_and_image_context.second));
  }

  base::WaitableEvent event;
  auto callback = base::BindOnce(
      [](std::vector<std::unique_ptr<ImageContextImpl>> render_passes,
         std::unique_ptr<SkiaOutputSurfaceImplOnGpu> impl_on_gpu,
         base::WaitableEvent* event) {
        if (!render_passes.empty())
          impl_on_gpu->RemoveRenderPassResource(std::move(render_passes));
        impl_on_gpu = nullptr;
        event->Signal();
      },
      std::move(render_pass_image_contexts), std::move(impl_on_gpu_), &event);
  ScheduleGpuTask(std::move(callback), std::vector<gpu::SyncToken>());
  event.Wait();

  task_sequence_ = nullptr;
}

Project: Chrome

void SkiaOutputSurfaceImplTest::BlockMainThread() {
  wait_.Wait();
}

Project: Chrome

void SkiaOutputSurfaceImplTest::CheckSyncTokenOnGpuThread(
    const gpu::SyncToken& sync_token) {
  EXPECT_TRUE(
      gpu_service()->sync_point_manager()->IsSyncTokenReleased(sync_token));
  UnblockMainThread();
}

Project: Chrome

void SkiaOutputSurfaceImplTest::CopyRequestCallbackOnGpuThread(
    const SkColor output_color,
    const gfx::Rect& output_rect,
    const gfx::ColorSpace& color_space,
    std::unique_ptr<CopyOutputResult> result) {
  std::unique_ptr<SkBitmap> result_bitmap;
  result_bitmap = std::make_unique<SkBitmap>(result->AsSkBitmap());
  EXPECT_EQ(result_bitmap->width(), output_rect.width());
  EXPECT_EQ(result_bitmap->height(), output_rect.height());

  std::vector<SkPMColor> expected_pixels(
      output_rect.width() * output_rect.height(),
      SkPreMultiplyColor(output_color));
  SkBitmap expected;
  expected.installPixels(
      SkImageInfo::MakeN32Premul(output_rect.width(), output_rect.height(),
                                 color_space.ToSkColorSpace()),
      expected_pixels.data(), output_rect.width() * sizeof(SkColor));
  ExpectEquals(*result_bitmap.get(), expected);

  UnblockMainThread();
}

Project: Chrome

void SkiaOutputSurfaceImplTest::SetUpSkiaOutputSurfaceImpl() {
  const char enable_features[] = "VizDisplayCompositor,UseSkiaRenderer";
  const char disable_features[] = "";
  scoped_feature_list_ = std::make_unique<base::test::ScopedFeatureList>();
  scoped_feature_list_->InitFromCommandLine(enable_features, disable_features);
  gpu_service_holder_ = TestGpuServiceHolder::GetInstance();

  gpu::SurfaceHandle surface_handle_ = gpu::kNullSurfaceHandle;
  if (on_screen_) {
#if BUILDFLAG(ENABLE_VULKAN) && defined(USE_X11)
    surface_handle_ = gpu::CreateNativeWindow(kSurfaceRect);
#else
    NOTREACHED();
#endif
  }
  output_surface_ = SkiaOutputSurfaceImpl::Create(
      std::make_unique<SkiaOutputSurfaceDependencyImpl>(gpu_service(),
                                                        surface_handle_),
      RendererSettings());
  output_surface_->BindToClient(output_surface_client_.get());
}

Project: Chrome

  SkiaOutputSurfaceImplTest()
      : output_surface_client_(std::make_unique<cc::FakeOutputSurfaceClient>()),
        wait_(base::WaitableEvent::ResetPolicy::AUTOMATIC,
              base::WaitableEvent::InitialState::NOT_SIGNALED),
        on_screen_(GetParam()) {}

Project: Chrome

void SkiaOutputSurfaceImplTest::UnblockMainThread() {
  DCHECK(!wait_.IsSignaled());
  wait_.Signal();
}

Project: Chrome

  GpuServiceImpl* gpu_service() { return gpu_service_holder_->gpu_service(); }