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;
}