v8 js代码与canvas的绘制

 


    v8::MaybeLocal<v8::Value> maybe_result;
    if (V8ScriptRunner::CompileScript(script_state, *classic_script,
                                      compile_options, no_cache_reason,
                                      host_defined_options)
            .ToLocal(&script)) {
      maybe_result = V8ScriptRunner::RunCompiledScript(
          isolate, script, host_defined_options, execution_context);
      probe::DidProduceCompilationCache(
          probe::ToCoreProbeSink(execution_context), *classic_script, script);

html:

查看代码
 <!DOCTYPE html>
<html>
<body>

<canvas id="myCanvas" width="200" height="100" style="border:1px solid #d3d3d3;">

<script>

var c=document.getElementById("myCanvas");
var ctx=c.getContext("2d");
ctx.moveTo(0,0);
ctx.lineTo(200,100);
ctx.stroke();

</script>

</body>
</html>

对与 canvas context的 ctx.stroke();语句执行断点:(第一次会 textrueLayer 创建,以后直接获取)

scoped_refptr<TextureLayer> TextureLayer::CreateForMailbox(
    TextureLayerClient* client) {
  return scoped_refptr<TextureLayer>(new TextureLayer(client));
}

创建后返回 paintCanvas:

查看代码
 cc::PaintCanvas* CanvasRenderingContext2D::GetOrCreatePaintCanvas() {
  if (UNLIKELY(isContextLost()))
    return nullptr;
  if (LIKELY(canvas()->GetOrCreateCanvas2DLayerBridge()))
    return canvas()->GetCanvas2DLayerBridge()->GetPaintCanvas();
  return nullptr;
}

drawStroke,就是调用内部的drawInnerPath:

void BaseRenderingContext2D::stroke() {
  if (identifiability_study_helper_.ShouldUpdateBuilder()) {
    identifiability_study_helper_.UpdateBuilder(CanvasOps::kStroke);
  }
  DrawPathInternal(path_, CanvasRenderingContext2DState::kStrokePaintType,
                   SkPathFillType::kWinding, UsePaintCache::kDisabled);
}


void BaseRenderingContext2D::DrawPathInternal(
    const Path& path,
    CanvasRenderingContext2DState::PaintType paint_type,
    SkPathFillType fill_type,
    UsePaintCache use_paint_cache) {
  if (path.IsEmpty())
    return;

  SkPath sk_path = path.GetSkPath();
  gfx::RectF bounds(path.BoundingRect());
  if (std::isnan(bounds.x()) || std::isnan(bounds.y()) ||
      std::isnan(bounds.width()) || std::isnan(bounds.height()))
    return;
  sk_path.setFillType(fill_type);

  if (paint_type == CanvasRenderingContext2DState::kStrokePaintType)
    InflateStrokeRect(bounds);

  if (!GetOrCreatePaintCanvas())
    return;

  Draw<OverdrawOp::kNone>(
      [sk_path, use_paint_cache](cc::PaintCanvas* c,
                                 const cc::PaintFlags* flags)  // draw lambda
      { c->drawPath(sk_path, *flags, use_paint_cache); },
      [](const SkIRect& rect)  // overdraw test lambda
      { return false; },
      gfx::RectFToSkRect(bounds), paint_type,
      GetState().HasPattern(paint_type)
          ? CanvasRenderingContext2DState::kNonOpaqueImage
          : CanvasRenderingContext2DState::kNoImage,
      CanvasPerformanceMonitor::DrawType::kPath);
}

最终走到draw模板函数

template <BaseRenderingContext2D::OverdrawOp CurrentOverdrawOp,
          typename DrawFunc,
          typename DrawCoversClipBoundsFunc>
void BaseRenderingContext2D::Draw(
    const DrawFunc& draw_func,
    const DrawCoversClipBoundsFunc& draw_covers_clip_bounds,
    const SkRect& bounds,
    CanvasRenderingContext2DState::PaintType paint_type,
    CanvasRenderingContext2DState::ImageType image_type,
    CanvasPerformanceMonitor::DrawType draw_type) {
  if (!IsTransformInvertible())
    return;

  SkIRect clip_bounds;
  cc::PaintCanvas* paint_canvas = GetOrCreatePaintCanvas();
  if (!paint_canvas || !paint_canvas->getDeviceClipBounds(&clip_bounds))
    return;

  if (UNLIKELY(GetState().IsFilterUnresolved())) {
    // Resolving a filter requires allocating garbage-collected objects.
    PostDeferrableAction(WTF::Bind(
        &BaseRenderingContext2D::DrawInternal<CurrentOverdrawOp, DrawFunc,
                                              DrawCoversClipBoundsFunc>,
        WrapPersistent(this), draw_func, draw_covers_clip_bounds, bounds,
        paint_type, image_type, clip_bounds, draw_type));
  } else {
    DrawInternal<CurrentOverdrawOp, DrawFunc, DrawCoversClipBoundsFunc>(
        draw_func, draw_covers_clip_bounds, bounds, paint_type, image_type,
        clip_bounds, draw_type);
  }
}

走到drawInternal

template <BaseRenderingContext2D::OverdrawOp CurrentOverdrawOp,
          typename DrawFunc,
          typename DrawCoversClipBoundsFunc>
void BaseRenderingContext2D::DrawInternal(
    const DrawFunc& draw_func,
    const DrawCoversClipBoundsFunc& draw_covers_clip_bounds,
    const SkRect& bounds,
    CanvasRenderingContext2DState::PaintType paint_type,
    CanvasRenderingContext2DState::ImageType image_type,
    const SkIRect& clip_bounds,
    CanvasPerformanceMonitor::DrawType draw_type) {
  const CanvasRenderingContext2DState& state = GetState();
  SkBlendMode global_composite = state.GlobalComposite();
  if (IsFullCanvasCompositeMode(global_composite) || StateHasFilter() ||
      (state.ShouldDrawShadows() &&
       ShouldUseDropShadowPaintFilter(paint_type, image_type))) {
    CompositedDraw(draw_func, GetPaintCanvasForDraw(clip_bounds, draw_type),
                   paint_type, image_type);
  } else if (global_composite == SkBlendMode::kSrc) {
    ClearCanvasForSrcCompositeOp();  // Takes care of CheckOverdraw()
    const cc::PaintFlags* flags =
        state.GetFlags(paint_type, kDrawForegroundOnly, image_type);
    draw_func(GetPaintCanvasForDraw(clip_bounds, draw_type), flags);
  } else {
    SkIRect dirty_rect;
    if (ComputeDirtyRect(gfx::SkRectToRectF(bounds), clip_bounds,
                         &dirty_rect)) {
      const cc::PaintFlags* flags =
          state.GetFlags(paint_type, kDrawShadowAndForeground, image_type);
      if (paint_type != CanvasRenderingContext2DState::kStrokePaintType &&
          draw_covers_clip_bounds(clip_bounds)) {
        // Because CurrentOverdrawOp is a template argument the following branch
        // is optimized-out at compile time.
        if (CurrentOverdrawOp != OverdrawOp::kNone) {
          CheckOverdraw(bounds, flags, image_type, CurrentOverdrawOp);
        }
      }
      draw_func(GetPaintCanvasForDraw(dirty_rect, draw_type), flags);
    }

 

 

 

canvas限制相关:


std::unique_ptr<CanvasResourceProvider>
CanvasResourceProvider::CreateSharedImageProvider(
    const SkImageInfo& info,
    cc::PaintFlags::FilterQuality filter_quality,
    ShouldInitialize should_initialize,
    base::WeakPtr<WebGraphicsContext3DProviderWrapper> context_provider_wrapper,
    RasterMode raster_mode,
    bool is_origin_top_left,
    uint32_t shared_image_usage_flags) {
  // IsGpuCompositingEnabled can re-create the context if it has been lost, do
  // this up front so that we can fail early and not expose ourselves to
  // use after free bugs (crbug.com/1126424)
  const bool is_gpu_compositing_enabled =
      SharedGpuContext::IsGpuCompositingEnabled();

  // If the context is lost we don't want to re-create it here, the resulting
  // resource provider would be invalid anyway
  if (!context_provider_wrapper ||
      context_provider_wrapper->ContextProvider()->IsContextLost())
    return nullptr;

  const auto& capabilities =
      context_provider_wrapper->ContextProvider()->GetCapabilities();
  bool skia_use_dawn =
      raster_mode == RasterMode::kGPU &&
      base::FeatureList::IsEnabled(blink::features::kDawn2dCanvas);
  // TODO(senorblanco): once Dawn reports maximum texture size, Dawn Canvas
  // should respect it.  http://crbug.com/1082760
  if (!skia_use_dawn && (info.width() < 1 || info.height() < 1 ||
                         info.width() > capabilities.max_texture_size ||
                         info.height() > capabilities.max_texture_size)) {
    return nullptr;
  }

  const bool is_accelerated = raster_mode == RasterMode::kGPU;

  SkImageInfo adjusted_info = info;
  // TODO(https://crbug.com/1210946): Pass in info as is for all cases.
  // Overriding the info to use RGBA instead of N32 is needed because code
  // elsewhere assumes RGBA. OTOH the software path seems to be assuming N32
  // somewhere in the later pipeline but for offscreen canvas only.
  if (!(shared_image_usage_flags & gpu::SHARED_IMAGE_USAGE_WEBGPU)) {
    adjusted_info = adjusted_info.makeColorType(
        is_accelerated && info.colorType() != kRGBA_F16_SkColorType
            ? kRGBA_8888_SkColorType
            : info.colorType());
  }

  const bool is_gpu_memory_buffer_image_allowed =
      is_gpu_compositing_enabled && IsGMBAllowed(adjusted_info, capabilities) &&
      Platform::Current()->GetGpuMemoryBufferManager();

  if (raster_mode == RasterMode::kCPU && !is_gpu_memory_buffer_image_allowed)
    return nullptr;

  // If we cannot use overlay, we have to remove the scanout flag and the
  // concurrent read write flag.
  // TODO(junov, vasilyt): capabilities.texture_storage_image is being used
  // as a proxy for determining whether SHARED_IMAGE_USAGE_SCANOUT is supported.
  // it would be preferable to have a dedicated capability bit for this.
  if (!is_gpu_memory_buffer_image_allowed ||
      (is_accelerated && !capabilities.texture_storage_image)) {
    shared_image_usage_flags &= ~gpu::SHARED_IMAGE_USAGE_CONCURRENT_READ_WRITE;
    shared_image_usage_flags &= ~gpu::SHARED_IMAGE_USAGE_SCANOUT;
  }

#if BUILDFLAG(IS_MAC)
  if ((shared_image_usage_flags & gpu::SHARED_IMAGE_USAGE_SCANOUT) &&
      is_accelerated && adjusted_info.colorType() == kRGBA_8888_SkColorType) {
    // GPU-accelerated scannout usage on Mac uses IOSurface.  Must switch from
    // RGBA_8888 to BGRA_8888 in that case.
    adjusted_info = adjusted_info.makeColorType(kBGRA_8888_SkColorType);
  }
#endif

  auto provider = std::make_unique<CanvasResourceProviderSharedImage>(
      adjusted_info, filter_quality, context_provider_wrapper,
      is_origin_top_left, is_accelerated, skia_use_dawn,
      shared_image_usage_flags);
  if (provider->IsValid()) {
    if (should_initialize ==
        CanvasResourceProvider::ShouldInitialize::kCallClear)
      provider->Clear();
    return provider;
  }

  return nullptr;
}

 

posted @ 2023-03-23 16:00  Bigben  阅读(127)  评论(0编辑  收藏  举报