| /* | |
| * Copyright 2012 Google Inc. | |
| * | |
| * Use of this source code is governed by a BSD-style license that can be | |
| * found in the LICENSE file. | |
| */ | |
| #include "tools/debugger/DrawCommand.h" | |
| #include "include/core/SkAlphaType.h" | |
| #include "include/core/SkBitmap.h" | |
| #include "include/core/SkBlendMode.h" | |
| #include "include/core/SkBlurTypes.h" | |
| #include "include/core/SkClipOp.h" | |
| #include "include/core/SkColorFilter.h" | |
| #include "include/core/SkColorType.h" | |
| #include "include/core/SkDrawable.h" | |
| #include "include/core/SkFlattenable.h" | |
| #include "include/core/SkFont.h" | |
| #include "include/core/SkFontTypes.h" | |
| #include "include/core/SkImageFilter.h" | |
| #include "include/core/SkImageInfo.h" | |
| #include "include/core/SkMaskFilter.h" | |
| #include "include/core/SkPathEffect.h" | |
| #include "include/core/SkPathTypes.h" | |
| #include "include/core/SkPicture.h" | |
| #include "include/core/SkPixmap.h" | |
| #include "include/core/SkPoint3.h" | |
| #include "include/core/SkRSXform.h" | |
| #include "include/core/SkSamplingOptions.h" | |
| #include "include/core/SkSize.h" | |
| #include "include/core/SkStream.h" | |
| #include "include/core/SkTypeface.h" | |
| #include "include/private/SkDebug.h" | |
| #include "include/private/SkMalloc.h" | |
| #include "include/private/SkTo.h" | |
| #include "include/utils/SkShadowUtils.h" | |
| #include "src/core/SkAutoMalloc.h" | |
| #include "src/core/SkCanvasPriv.h" | |
| #include "src/core/SkFontPriv.h" | |
| #include "src/core/SkMaskFilterBase.h" | |
| #include "src/core/SkPaintDefaults.h" | |
| #include "src/core/SkPathEffectBase.h" | |
| #include "src/core/SkRectPriv.h" | |
| #include "src/core/SkTLazy.h" | |
| #include "src/core/SkTextBlobPriv.h" | |
| #include "src/core/SkWriteBuffer.h" | |
| #include "src/image/SkImage_Base.h" | |
| #include "src/utils/SkJSONWriter.h" | |
| #include "tools/UrlDataManager.h" | |
| #include "tools/debugger/DebugLayerManager.h" | |
| #include "tools/debugger/JsonWriteBuffer.h" | |
| #include <algorithm> | |
| #include <cstring> | |
| #include <utility> | |
| class GrDirectContext; | |
| #if defined(SK_GANESH) | |
| #include "include/gpu/ganesh/GrRecordingContext.h" | |
| #include "include/private/gpu/ganesh/GrImageContext.h" | |
| #endif | |
| #define DEBUGCANVAS_ATTRIBUTE_DUMP "dump" | |
| #define DEBUGCANVAS_ATTRIBUTE_COMMAND "command" | |
| #define DEBUGCANVAS_ATTRIBUTE_VISIBLE "visible" | |
| #define DEBUGCANVAS_ATTRIBUTE_MATRIX "matrix" | |
| #define DEBUGCANVAS_ATTRIBUTE_COORDS "coords" | |
| #define DEBUGCANVAS_ATTRIBUTE_EDGING "edging" | |
| #define DEBUGCANVAS_ATTRIBUTE_HINTING "hinting" | |
| #define DEBUGCANVAS_ATTRIBUTE_BOUNDS "bounds" | |
| #define DEBUGCANVAS_ATTRIBUTE_PAINT "paint" | |
| #define DEBUGCANVAS_ATTRIBUTE_OUTER "outer" | |
| #define DEBUGCANVAS_ATTRIBUTE_INNER "inner" | |
| #define DEBUGCANVAS_ATTRIBUTE_MODE "mode" | |
| #define DEBUGCANVAS_ATTRIBUTE_POINTS "points" | |
| #define DEBUGCANVAS_ATTRIBUTE_PATH "path" | |
| #define DEBUGCANVAS_ATTRIBUTE_CLUSTERS "clusters" | |
| #define DEBUGCANVAS_ATTRIBUTE_TEXT "text" | |
| #define DEBUGCANVAS_ATTRIBUTE_COLOR "color" | |
| #define DEBUGCANVAS_ATTRIBUTE_BLENDMODE "blendMode" | |
| #define DEBUGCANVAS_ATTRIBUTE_SAMPLING "sampling" | |
| #define DEBUGCANVAS_ATTRIBUTE_STYLE "style" | |
| #define DEBUGCANVAS_ATTRIBUTE_STROKEWIDTH "strokeWidth" | |
| #define DEBUGCANVAS_ATTRIBUTE_STROKEMITER "strokeMiter" | |
| #define DEBUGCANVAS_ATTRIBUTE_STROKEJOIN "strokeJoin" | |
| #define DEBUGCANVAS_ATTRIBUTE_CAP "cap" | |
| #define DEBUGCANVAS_ATTRIBUTE_ANTIALIAS "antiAlias" | |
| #define DEBUGCANVAS_ATTRIBUTE_DITHER "dither" | |
| #define DEBUGCANVAS_ATTRIBUTE_FAKEBOLDTEXT "fakeBoldText" | |
| #define DEBUGCANVAS_ATTRIBUTE_LINEARTEXT "linearText" | |
| #define DEBUGCANVAS_ATTRIBUTE_SUBPIXELTEXT "subpixelText" | |
| #define DEBUGCANVAS_ATTRIBUTE_EMBEDDEDBITMAPTEXT "embeddedBitmapText" | |
| #define DEBUGCANVAS_ATTRIBUTE_AUTOHINTING "forceAutoHinting" | |
| #define DEBUGCANVAS_ATTRIBUTE_REGION "region" | |
| #define DEBUGCANVAS_ATTRIBUTE_REGIONOP "op" | |
| #define DEBUGCANVAS_ATTRIBUTE_BLUR "blur" | |
| #define DEBUGCANVAS_ATTRIBUTE_SIGMA "sigma" | |
| #define DEBUGCANVAS_ATTRIBUTE_TEXTSIZE "textSize" | |
| #define DEBUGCANVAS_ATTRIBUTE_TEXTSCALEX "textScaleX" | |
| #define DEBUGCANVAS_ATTRIBUTE_DASHING "dashing" | |
| #define DEBUGCANVAS_ATTRIBUTE_INTERVALS "intervals" | |
| #define DEBUGCANVAS_ATTRIBUTE_PHASE "phase" | |
| #define DEBUGCANVAS_ATTRIBUTE_FILLTYPE "fillType" | |
| #define DEBUGCANVAS_ATTRIBUTE_VERBS "verbs" | |
| #define DEBUGCANVAS_ATTRIBUTE_NAME "name" | |
| #define DEBUGCANVAS_ATTRIBUTE_DATA "data" | |
| #define DEBUGCANVAS_ATTRIBUTE_VALUES "values" | |
| #define DEBUGCANVAS_ATTRIBUTE_SHADER "shader" | |
| #define DEBUGCANVAS_ATTRIBUTE_PATHEFFECT "pathEffect" | |
| #define DEBUGCANVAS_ATTRIBUTE_MASKFILTER "maskFilter" | |
| #define DEBUGCANVAS_ATTRIBUTE_BACKDROP "backdrop" | |
| #define DEBUGCANVAS_ATTRIBUTE_COLORFILTER "colorfilter" | |
| #define DEBUGCANVAS_ATTRIBUTE_IMAGEFILTER "imagefilter" | |
| #define DEBUGCANVAS_ATTRIBUTE_IMAGE "image" | |
| #define DEBUGCANVAS_ATTRIBUTE_IMAGE_INDEX "imageIndex" | |
| #define DEBUGCANVAS_ATTRIBUTE_SRC "src" | |
| #define DEBUGCANVAS_ATTRIBUTE_DST "dst" | |
| #define DEBUGCANVAS_ATTRIBUTE_STRICT "strict" | |
| #define DEBUGCANVAS_ATTRIBUTE_X "x" | |
| #define DEBUGCANVAS_ATTRIBUTE_Y "y" | |
| #define DEBUGCANVAS_ATTRIBUTE_RUNS "runs" | |
| #define DEBUGCANVAS_ATTRIBUTE_POSITIONS "positions" | |
| #define DEBUGCANVAS_ATTRIBUTE_GLYPHS "glyphs" | |
| #define DEBUGCANVAS_ATTRIBUTE_FONT "font" | |
| #define DEBUGCANVAS_ATTRIBUTE_TYPEFACE "typeface" | |
| #define DEBUGCANVAS_ATTRIBUTE_CUBICS "cubics" | |
| #define DEBUGCANVAS_ATTRIBUTE_COLORS "colors" | |
| #define DEBUGCANVAS_ATTRIBUTE_TEXTURECOORDS "textureCoords" | |
| #define DEBUGCANVAS_ATTRIBUTE_STARTANGLE "startAngle" | |
| #define DEBUGCANVAS_ATTRIBUTE_SWEEPANGLE "sweepAngle" | |
| #define DEBUGCANVAS_ATTRIBUTE_USECENTER "useCenter" | |
| #define DEBUGCANVAS_ATTRIBUTE_SHORTDESC "shortDesc" | |
| #define DEBUGCANVAS_ATTRIBUTE_UNIQUE_ID "uniqueID" | |
| #define DEBUGCANVAS_ATTRIBUTE_WIDTH "width" | |
| #define DEBUGCANVAS_ATTRIBUTE_HEIGHT "height" | |
| #define DEBUGCANVAS_ATTRIBUTE_ALPHA "alpha" | |
| #define DEBUGCANVAS_ATTRIBUTE_LATTICE "lattice" | |
| #define DEBUGCANVAS_ATTRIBUTE_LATTICEXCOUNT "xCount" | |
| #define DEBUGCANVAS_ATTRIBUTE_LATTICEYCOUNT "yCount" | |
| #define DEBUGCANVAS_ATTRIBUTE_LATTICEXDIVS "xDivs" | |
| #define DEBUGCANVAS_ATTRIBUTE_LATTICEYDIVS "yDivs" | |
| #define DEBUGCANVAS_ATTRIBUTE_LATTICEFLAGS "flags" | |
| #define DEBUGCANVAS_ATTRIBUTE_ZPLANE "zPlane" | |
| #define DEBUGCANVAS_ATTRIBUTE_LIGHTPOSITION "lightPositions" | |
| #define DEBUGCANVAS_ATTRIBUTE_AMBIENTCOLOR "ambientColor" | |
| #define DEBUGCANVAS_ATTRIBUTE_SPOTCOLOR "spotColor" | |
| #define DEBUGCANVAS_ATTRIBUTE_LIGHTRADIUS "lightRadius" | |
| #define DEBUGCANVAS_ATTRIBUTE_LAYERNODEID "layerNodeId" | |
| #define DEBUGCANVAS_VERB_MOVE "move" | |
| #define DEBUGCANVAS_VERB_LINE "line" | |
| #define DEBUGCANVAS_VERB_QUAD "quad" | |
| #define DEBUGCANVAS_VERB_CUBIC "cubic" | |
| #define DEBUGCANVAS_VERB_CONIC "conic" | |
| #define DEBUGCANVAS_VERB_CLOSE "close" | |
| #define DEBUGCANVAS_STYLE_STROKE "stroke" | |
| #define DEBUGCANVAS_STYLE_STROKEANDFILL "strokeAndFill" | |
| #define DEBUGCANVAS_POINTMODE_POINTS "points" | |
| #define DEBUGCANVAS_POINTMODE_LINES "lines" | |
| #define DEBUGCANVAS_POINTMODE_POLYGON "polygon" | |
| #define DEBUGCANVAS_CLIPOP_DIFFERENCE "difference" | |
| #define DEBUGCANVAS_CLIPOP_INTERSECT "intersect" | |
| #define DEBUGCANVAS_BLURSTYLE_NORMAL "normal" | |
| #define DEBUGCANVAS_BLURSTYLE_SOLID "solid" | |
| #define DEBUGCANVAS_BLURSTYLE_OUTER "outer" | |
| #define DEBUGCANVAS_BLURSTYLE_INNER "inner" | |
| #define DEBUGCANVAS_FILLTYPE_WINDING "winding" | |
| #define DEBUGCANVAS_FILLTYPE_EVENODD "evenOdd" | |
| #define DEBUGCANVAS_FILLTYPE_INVERSEWINDING "inverseWinding" | |
| #define DEBUGCANVAS_FILLTYPE_INVERSEEVENODD "inverseEvenOdd" | |
| #define DEBUGCANVAS_CAP_BUTT "butt" | |
| #define DEBUGCANVAS_CAP_ROUND "round" | |
| #define DEBUGCANVAS_CAP_SQUARE "square" | |
| #define DEBUGCANVAS_MITER_JOIN "miter" | |
| #define DEBUGCANVAS_ROUND_JOIN "round" | |
| #define DEBUGCANVAS_BEVEL_JOIN "bevel" | |
| #define DEBUGCANVAS_COLORTYPE_ARGB4444 "ARGB4444" | |
| #define DEBUGCANVAS_COLORTYPE_RGBA8888 "RGBA8888" | |
| #define DEBUGCANVAS_COLORTYPE_BGRA8888 "BGRA8888" | |
| #define DEBUGCANVAS_COLORTYPE_565 "565" | |
| #define DEBUGCANVAS_COLORTYPE_GRAY8 "Gray8" | |
| #define DEBUGCANVAS_COLORTYPE_ALPHA8 "Alpha8" | |
| #define DEBUGCANVAS_ALPHATYPE_OPAQUE "opaque" | |
| #define DEBUGCANVAS_ALPHATYPE_PREMUL "premul" | |
| #define DEBUGCANVAS_ALPHATYPE_UNPREMUL "unpremul" | |
| #define DEBUGCANVAS_ALPHATYPE_UNKNOWN "unknown" | |
| #define DEBUGCANVAS_HINTING_NONE "none" | |
| #define DEBUGCANVAS_HINTING_SLIGHT "slight" | |
| #define DEBUGCANVAS_HINTING_NORMAL "normal" | |
| #define DEBUGCANVAS_HINTING_FULL "full" | |
| #define DEBUGCANVAS_EDGING_ALIAS "alias" | |
| #define DEBUGCANVAS_EDGING_ANTIALIAS "antialias" | |
| #define DEBUGCANVAS_EDGING_SUBPIXELANTIALIAS "subpixelantialias" | |
| #define DEBUGCANVAS_SHADOWFLAG_TRANSPARENT_OCC "transparentOccluder" | |
| #define DEBUGCANVAS_SHADOWFLAG_GEOMETRIC_ONLY "geometricOnly" | |
| static SkString* str_append(SkString* str, const SkRect& r) { | |
| str->appendf(" [%g %g %g %g]", r.left(), r.top(), r.right(), r.bottom()); | |
| return str; | |
| } | |
| DrawCommand::DrawCommand(OpType type) : fOpType(type), fVisible(true) {} | |
| const char* DrawCommand::GetCommandString(OpType type) { | |
| switch (type) { | |
| case kBeginDrawPicture_OpType: return "BeginDrawPicture"; | |
| case kClear_OpType: return "DrawClear"; | |
| case kClipPath_OpType: return "ClipPath"; | |
| case kClipRegion_OpType: return "ClipRegion"; | |
| case kClipRect_OpType: return "ClipRect"; | |
| case kClipRRect_OpType: return "ClipRRect"; | |
| case kResetClip_OpType: return "ResetClip"; | |
| case kConcat_OpType: return "Concat"; | |
| case kConcat44_OpType: return "Concat44"; | |
| case kDrawAnnotation_OpType: return "DrawAnnotation"; | |
| case kDrawBitmap_OpType: return "DrawBitmap"; | |
| case kDrawBitmapRect_OpType: return "DrawBitmapRect"; | |
| case kDrawDRRect_OpType: return "DrawDRRect"; | |
| case kDrawImage_OpType: return "DrawImage"; | |
| case kDrawImageLattice_OpType: return "DrawImageLattice"; | |
| case kDrawImageRect_OpType: return "DrawImageRect"; | |
| case kDrawImageRectLayer_OpType: return "DrawImageRectLayer"; | |
| case kDrawOval_OpType: return "DrawOval"; | |
| case kDrawPaint_OpType: return "DrawPaint"; | |
| case kDrawPatch_OpType: return "DrawPatch"; | |
| case kDrawPath_OpType: return "DrawPath"; | |
| case kDrawArc_OpType: return "DrawArc"; | |
| case kDrawPoints_OpType: return "DrawPoints"; | |
| case kDrawRect_OpType: return "DrawRect"; | |
| case kDrawRRect_OpType: return "DrawRRect"; | |
| case kDrawRegion_OpType: return "DrawRegion"; | |
| case kDrawShadow_OpType: return "DrawShadow"; | |
| case kDrawTextBlob_OpType: return "DrawTextBlob"; | |
| case kDrawVertices_OpType: return "DrawVertices"; | |
| case kDrawAtlas_OpType: return "DrawAtlas"; | |
| case kDrawDrawable_OpType: return "DrawDrawable"; | |
| case kDrawEdgeAAQuad_OpType: return "DrawEdgeAAQuad"; | |
| case kDrawEdgeAAImageSet_OpType: return "DrawEdgeAAImageSet"; | |
| case kEndDrawPicture_OpType: return "EndDrawPicture"; | |
| case kRestore_OpType: return "Restore"; | |
| case kSave_OpType: return "Save"; | |
| case kSaveLayer_OpType: return "SaveLayer"; | |
| case kSetMatrix_OpType: return "SetMatrix"; | |
| case kSetM44_OpType: return "SetM44"; | |
| default: | |
| SkDEBUGFAILF("OpType error 0x%08x\n", (unsigned int)type); | |
| break; | |
| } | |
| SkDEBUGFAIL("DrawType UNUSED\n"); | |
| return nullptr; | |
| } | |
| void DrawCommand::toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const { | |
| writer.appendCString(DEBUGCANVAS_ATTRIBUTE_COMMAND, GetCommandString(fOpType)); | |
| writer.appendBool(DEBUGCANVAS_ATTRIBUTE_VISIBLE, this->isVisible()); | |
| } | |
| namespace { | |
| void xlate_and_scale_to_bounds(SkCanvas* canvas, const SkRect& bounds) { | |
| const SkISize& size = canvas->getBaseLayerSize(); | |
| static const SkScalar kInsetFrac = 0.9f; // Leave a border around object | |
| canvas->translate(size.fWidth / 2.0f, size.fHeight / 2.0f); | |
| if (bounds.width() > bounds.height()) { | |
| canvas->scale(SkDoubleToScalar((kInsetFrac * size.fWidth) / bounds.width()), | |
| SkDoubleToScalar((kInsetFrac * size.fHeight) / bounds.width())); | |
| } else { | |
| canvas->scale(SkDoubleToScalar((kInsetFrac * size.fWidth) / bounds.height()), | |
| SkDoubleToScalar((kInsetFrac * size.fHeight) / bounds.height())); | |
| } | |
| canvas->translate(-bounds.centerX(), -bounds.centerY()); | |
| } | |
| void render_path(SkCanvas* canvas, const SkPath& path) { | |
| canvas->clear(0xFFFFFFFF); | |
| const SkRect& bounds = path.getBounds(); | |
| if (bounds.isEmpty()) { | |
| return; | |
| } | |
| SkAutoCanvasRestore acr(canvas, true); | |
| xlate_and_scale_to_bounds(canvas, bounds); | |
| SkPaint p; | |
| p.setColor(SK_ColorBLACK); | |
| p.setStyle(SkPaint::kStroke_Style); | |
| canvas->drawPath(path, p); | |
| } | |
| void render_region(SkCanvas* canvas, const SkRegion& region) { | |
| canvas->clear(0xFFFFFFFF); | |
| const SkIRect& bounds = region.getBounds(); | |
| if (bounds.isEmpty()) { | |
| return; | |
| } | |
| SkAutoCanvasRestore acr(canvas, true); | |
| xlate_and_scale_to_bounds(canvas, SkRect::Make(bounds)); | |
| SkPaint p; | |
| p.setColor(SK_ColorBLACK); | |
| p.setStyle(SkPaint::kStroke_Style); | |
| canvas->drawRegion(region, p); | |
| } | |
| void render_rrect(SkCanvas* canvas, const SkRRect& rrect) { | |
| canvas->clear(0xFFFFFFFF); | |
| canvas->save(); | |
| const SkRect& bounds = rrect.getBounds(); | |
| xlate_and_scale_to_bounds(canvas, bounds); | |
| SkPaint p; | |
| p.setColor(SK_ColorBLACK); | |
| p.setStyle(SkPaint::kStroke_Style); | |
| canvas->drawRRect(rrect, p); | |
| canvas->restore(); | |
| } | |
| void render_drrect(SkCanvas* canvas, const SkRRect& outer, const SkRRect& inner) { | |
| canvas->clear(0xFFFFFFFF); | |
| canvas->save(); | |
| const SkRect& bounds = outer.getBounds(); | |
| xlate_and_scale_to_bounds(canvas, bounds); | |
| SkPaint p; | |
| p.setColor(SK_ColorBLACK); | |
| p.setStyle(SkPaint::kStroke_Style); | |
| canvas->drawDRRect(outer, inner, p); | |
| canvas->restore(); | |
| } | |
| void render_shadow(SkCanvas* canvas, const SkPath& path, SkDrawShadowRec rec) { | |
| canvas->clear(0xFFFFFFFF); | |
| const SkRect& bounds = path.getBounds(); | |
| if (bounds.isEmpty()) { | |
| return; | |
| } | |
| SkAutoCanvasRestore acr(canvas, true); | |
| xlate_and_scale_to_bounds(canvas, bounds); | |
| rec.fAmbientColor = SK_ColorBLACK; | |
| rec.fSpotColor = SK_ColorBLACK; | |
| canvas->private_draw_shadow_rec(path, rec); | |
| } | |
| void apply_paint_blend_mode(const SkPaint& paint, SkJSONWriter& writer) { | |
| const auto mode = paint.getBlendMode_or(SkBlendMode::kSrcOver); | |
| if (mode != SkBlendMode::kSrcOver) { | |
| writer.appendCString(DEBUGCANVAS_ATTRIBUTE_BLENDMODE, SkBlendMode_Name(mode)); | |
| } | |
| } | |
| } // namespace | |
| void DrawCommand::MakeJsonColor(SkJSONWriter& writer, const SkColor color) { | |
| writer.beginArray(nullptr, false); | |
| writer.appendS32(SkColorGetA(color)); | |
| writer.appendS32(SkColorGetR(color)); | |
| writer.appendS32(SkColorGetG(color)); | |
| writer.appendS32(SkColorGetB(color)); | |
| writer.endArray(); | |
| } | |
| void DrawCommand::MakeJsonColor4f(SkJSONWriter& writer, const SkColor4f& color) { | |
| writer.beginArray(nullptr, false); | |
| writer.appendFloat(color.fA); | |
| writer.appendFloat(color.fR); | |
| writer.appendFloat(color.fG); | |
| writer.appendFloat(color.fB); | |
| writer.endArray(); | |
| } | |
| void DrawCommand::MakeJsonPoint(SkJSONWriter& writer, const SkPoint& point) { | |
| writer.beginArray(nullptr, false); | |
| writer.appendFloat(point.x()); | |
| writer.appendFloat(point.y()); | |
| writer.endArray(); | |
| } | |
| void DrawCommand::MakeJsonPoint(SkJSONWriter& writer, SkScalar x, SkScalar y) { | |
| writer.beginArray(nullptr, false); | |
| writer.appendFloat(x); | |
| writer.appendFloat(y); | |
| writer.endArray(); | |
| } | |
| void DrawCommand::MakeJsonPoint3(SkJSONWriter& writer, const SkPoint3& point) { | |
| writer.beginArray(nullptr, false); | |
| writer.appendFloat(point.x()); | |
| writer.appendFloat(point.y()); | |
| writer.appendFloat(point.z()); | |
| writer.endArray(); | |
| } | |
| void DrawCommand::MakeJsonRect(SkJSONWriter& writer, const SkRect& rect) { | |
| writer.beginArray(nullptr, false); | |
| writer.appendFloat(rect.left()); | |
| writer.appendFloat(rect.top()); | |
| writer.appendFloat(rect.right()); | |
| writer.appendFloat(rect.bottom()); | |
| writer.endArray(); | |
| } | |
| void DrawCommand::MakeJsonIRect(SkJSONWriter& writer, const SkIRect& rect) { | |
| writer.beginArray(nullptr, false); | |
| writer.appendS32(rect.left()); | |
| writer.appendS32(rect.top()); | |
| writer.appendS32(rect.right()); | |
| writer.appendS32(rect.bottom()); | |
| writer.endArray(); | |
| } | |
| static void make_json_rrect(SkJSONWriter& writer, const SkRRect& rrect) { | |
| writer.beginArray(nullptr, false); | |
| DrawCommand::MakeJsonRect(writer, rrect.rect()); | |
| DrawCommand::MakeJsonPoint(writer, rrect.radii(SkRRect::kUpperLeft_Corner)); | |
| DrawCommand::MakeJsonPoint(writer, rrect.radii(SkRRect::kUpperRight_Corner)); | |
| DrawCommand::MakeJsonPoint(writer, rrect.radii(SkRRect::kLowerRight_Corner)); | |
| DrawCommand::MakeJsonPoint(writer, rrect.radii(SkRRect::kLowerLeft_Corner)); | |
| writer.endArray(); | |
| } | |
| void DrawCommand::MakeJsonMatrix(SkJSONWriter& writer, const SkMatrix& matrix) { | |
| writer.beginArray(); | |
| for (int r = 0; r < 3; ++r) { | |
| writer.beginArray(nullptr, false); | |
| for (int c = 0; c < 3; ++c) { | |
| writer.appendFloat(matrix[r * 3 + c]); | |
| } | |
| writer.endArray(); | |
| } | |
| writer.endArray(); | |
| } | |
| void DrawCommand::MakeJsonMatrix44(SkJSONWriter& writer, const SkM44& matrix) { | |
| writer.beginArray(); | |
| for (int r = 0; r < 4; ++r) { | |
| writer.beginArray(nullptr, false); | |
| for (int c = 0; c < 4; ++c) { | |
| writer.appendFloat(matrix.rc(r, c)); | |
| } | |
| writer.endArray(); | |
| } | |
| writer.endArray(); | |
| } | |
| void DrawCommand::MakeJsonPath(SkJSONWriter& writer, const SkPath& path) { | |
| writer.beginObject(); | |
| SkDynamicMemoryWStream wstream; | |
| path.dump(&wstream, false); | |
| auto data = wstream.detachAsData(); | |
| writer.appendString(DEBUGCANVAS_ATTRIBUTE_DUMP, | |
| static_cast<const char*>(data->data()), data->size()); | |
| switch (path.getFillType()) { | |
| case SkPathFillType::kWinding: | |
| writer.appendNString(DEBUGCANVAS_ATTRIBUTE_FILLTYPE, DEBUGCANVAS_FILLTYPE_WINDING); | |
| break; | |
| case SkPathFillType::kEvenOdd: | |
| writer.appendNString(DEBUGCANVAS_ATTRIBUTE_FILLTYPE, DEBUGCANVAS_FILLTYPE_EVENODD); | |
| break; | |
| case SkPathFillType::kInverseWinding: | |
| writer.appendNString(DEBUGCANVAS_ATTRIBUTE_FILLTYPE, | |
| DEBUGCANVAS_FILLTYPE_INVERSEWINDING); | |
| break; | |
| case SkPathFillType::kInverseEvenOdd: | |
| writer.appendNString(DEBUGCANVAS_ATTRIBUTE_FILLTYPE, | |
| DEBUGCANVAS_FILLTYPE_INVERSEEVENODD); | |
| break; | |
| } | |
| writer.beginArray(DEBUGCANVAS_ATTRIBUTE_VERBS); | |
| SkPath::Iter iter(path, false); | |
| while (auto rec = iter.next()) { | |
| if (rec->fVerb == SkPathVerb::kClose) { | |
| writer.appendNString(DEBUGCANVAS_VERB_CLOSE); | |
| continue; | |
| } | |
| writer.beginObject(); // verb | |
| SkSpan<const SkPoint> pts = rec->fPoints; | |
| switch (rec->fVerb) { | |
| case SkPathVerb::kLine: { | |
| writer.appendName(DEBUGCANVAS_VERB_LINE); | |
| MakeJsonPoint(writer, pts[1]); | |
| break; | |
| } | |
| case SkPathVerb::kQuad: { | |
| writer.beginArray(DEBUGCANVAS_VERB_QUAD); | |
| MakeJsonPoint(writer, pts[1]); | |
| MakeJsonPoint(writer, pts[2]); | |
| writer.endArray(); // quad coords | |
| break; | |
| } | |
| case SkPathVerb::kCubic: { | |
| writer.beginArray(DEBUGCANVAS_VERB_CUBIC); | |
| MakeJsonPoint(writer, pts[1]); | |
| MakeJsonPoint(writer, pts[2]); | |
| MakeJsonPoint(writer, pts[3]); | |
| writer.endArray(); // cubic coords | |
| break; | |
| } | |
| case SkPathVerb::kConic: { | |
| writer.beginArray(DEBUGCANVAS_VERB_CONIC); | |
| MakeJsonPoint(writer, pts[1]); | |
| MakeJsonPoint(writer, pts[2]); | |
| writer.appendFloat(rec->conicWeight()); | |
| writer.endArray(); // conic coords | |
| break; | |
| } | |
| case SkPathVerb::kMove: { | |
| writer.appendName(DEBUGCANVAS_VERB_MOVE); | |
| MakeJsonPoint(writer, pts[0]); | |
| break; | |
| } | |
| case SkPathVerb::kClose: | |
| // Unreachable | |
| break; | |
| } | |
| writer.endObject(); // verb | |
| } | |
| writer.endArray(); // verbs | |
| writer.endObject(); // path | |
| } | |
| void DrawCommand::MakeJsonRegion(SkJSONWriter& writer, const SkRegion& region) { | |
| // TODO: Actually serialize the rectangles, rather than just devolving to path | |
| MakeJsonPath(writer, region.getBoundaryPath()); | |
| } | |
| void DrawCommand::MakeJsonSampling(SkJSONWriter& writer, const SkSamplingOptions& sampling) { | |
| writer.beginObject(); | |
| writer.appendS32("maxAniso", sampling.maxAniso); | |
| writer.appendBool("useCubic", sampling.useCubic); | |
| writer.appendS32("filter", (int)sampling.filter); | |
| writer.appendS32("mipmap", (int)sampling.mipmap); | |
| writer.appendFloat("cubic.B", sampling.cubic.B); | |
| writer.appendFloat("cubic.C", sampling.cubic.C); | |
| writer.endObject(); | |
| } | |
| static const char* clipop_name(SkClipOp op) { | |
| switch (op) { | |
| case SkClipOp::kDifference: return DEBUGCANVAS_CLIPOP_DIFFERENCE; | |
| case SkClipOp::kIntersect: return DEBUGCANVAS_CLIPOP_INTERSECT; | |
| default: SkASSERT(false); return "<invalid region op>"; | |
| } | |
| } | |
| static const char* pointmode_name(SkCanvas::PointMode mode) { | |
| switch (mode) { | |
| case SkCanvas::kPoints_PointMode: return DEBUGCANVAS_POINTMODE_POINTS; | |
| case SkCanvas::kLines_PointMode: return DEBUGCANVAS_POINTMODE_LINES; | |
| case SkCanvas::kPolygon_PointMode: return DEBUGCANVAS_POINTMODE_POLYGON; | |
| default: SkASSERT(false); return "<invalid point mode>"; | |
| } | |
| } | |
| static void store_scalar(SkJSONWriter& writer, | |
| const char* key, | |
| SkScalar value, | |
| SkScalar defaultValue) { | |
| if (value != defaultValue) { | |
| writer.appendFloat(key, value); | |
| } | |
| } | |
| static void store_bool(SkJSONWriter& writer, const char* key, bool value, bool defaultValue) { | |
| if (value != defaultValue) { | |
| writer.appendBool(key, value); | |
| } | |
| } | |
| static SkString encode_data(sk_sp<const SkData> data, | |
| const char* contentType, | |
| UrlDataManager& urlDataManager) { | |
| return urlDataManager.addData(data, contentType); | |
| } | |
| void DrawCommand::flatten(const SkFlattenable* flattenable, | |
| SkJSONWriter& writer, | |
| UrlDataManager& urlDataManager) { | |
| SkBinaryWriteBuffer buffer(writer.getSerialProcs()); | |
| flattenable->flatten(buffer); | |
| sk_sp<SkData> data = buffer.snapshotAsData(); | |
| SkString url = encode_data(data, "application/octet-stream", urlDataManager); | |
| writer.appendCString(DEBUGCANVAS_ATTRIBUTE_NAME, flattenable->getTypeName()); | |
| writer.appendString(DEBUGCANVAS_ATTRIBUTE_DATA, url); | |
| writer.beginObject(DEBUGCANVAS_ATTRIBUTE_VALUES); | |
| JsonWriteBuffer jsonBuffer(&writer, &urlDataManager); | |
| flattenable->flatten(jsonBuffer); | |
| writer.endObject(); // values | |
| } | |
| // flattens an image to a Json stream, also called from shader flatten | |
| bool DrawCommand::flatten(const SkImage& image, | |
| SkJSONWriter& writer, | |
| UrlDataManager& urlDataManager) { | |
| // For MSKP files, there is no need to encode the image, | |
| // just report its id. | |
| if (urlDataManager.hasImageIndex()) { | |
| writer.appendName(DEBUGCANVAS_ATTRIBUTE_IMAGE_INDEX); | |
| writer.appendU64(urlDataManager.lookupImage(&image)); | |
| return true; | |
| } | |
| writer.beginObject(DEBUGCANVAS_ATTRIBUTE_IMAGE); | |
| size_t rowBytes = 4 * image.width(); | |
| SkAutoMalloc buffer(rowBytes * image.height()); | |
| SkImageInfo dstInfo = | |
| SkImageInfo::Make(image.dimensions(), kN32_SkColorType, kPremul_SkAlphaType); | |
| // "cheat" for this debug tool and use image's context | |
| GrDirectContext* dContext = nullptr; | |
| #if defined(SK_GANESH) | |
| dContext = GrAsDirectContext(as_IB(&image)->context()); | |
| #endif | |
| if (!image.readPixels(dContext, dstInfo, buffer.get(), rowBytes, 0, 0)) { | |
| SkDebugf("DrawCommand::flatten SkImage: readPixels failed\n"); | |
| writer.endObject(); | |
| return false; | |
| } | |
| SkBitmap bm; | |
| bm.installPixels(dstInfo, buffer.get(), rowBytes); | |
| SkSerialProcs procs = writer.getSerialProcs(); | |
| sk_sp<const SkData> encoded; | |
| if (procs.fImageProc) { | |
| sk_sp<SkImage> rasterImage = bm.asImage(); | |
| encoded = procs.fImageProc(rasterImage.get(), procs.fImageCtx); | |
| } | |
| if (encoded == nullptr || encoded->isEmpty()) { | |
| SkDebugf("DrawCommand::flatten SkImage: could not encode image\n"); | |
| writer.endObject(); | |
| return false; | |
| } | |
| if (!encoded->data()) { | |
| SkDebugf("DrawCommand::flatten SkImage: encoding as PNG produced zero length data\n"); | |
| writer.endObject(); | |
| return false; | |
| } | |
| SkString url = encode_data(encoded, "image/png", urlDataManager); | |
| writer.appendString(DEBUGCANVAS_ATTRIBUTE_DATA, url); | |
| writer.endObject(); | |
| return true; | |
| } | |
| static const char* color_type_name(SkColorType colorType) { | |
| switch (colorType) { | |
| case kARGB_4444_SkColorType: return DEBUGCANVAS_COLORTYPE_ARGB4444; | |
| case kRGBA_8888_SkColorType: return DEBUGCANVAS_COLORTYPE_RGBA8888; | |
| case kBGRA_8888_SkColorType: return DEBUGCANVAS_COLORTYPE_BGRA8888; | |
| case kRGB_565_SkColorType: return DEBUGCANVAS_COLORTYPE_565; | |
| case kGray_8_SkColorType: return DEBUGCANVAS_COLORTYPE_GRAY8; | |
| case kAlpha_8_SkColorType: return DEBUGCANVAS_COLORTYPE_ALPHA8; | |
| default: SkASSERT(false); return DEBUGCANVAS_COLORTYPE_RGBA8888; | |
| } | |
| } | |
| static const char* alpha_type_name(SkAlphaType alphaType) { | |
| switch (alphaType) { | |
| case kOpaque_SkAlphaType: return DEBUGCANVAS_ALPHATYPE_OPAQUE; | |
| case kPremul_SkAlphaType: return DEBUGCANVAS_ALPHATYPE_PREMUL; | |
| case kUnpremul_SkAlphaType: return DEBUGCANVAS_ALPHATYPE_UNPREMUL; | |
| default: SkASSERT(false); return DEBUGCANVAS_ALPHATYPE_OPAQUE; | |
| } | |
| } | |
| bool DrawCommand::flatten(const SkBitmap& bitmap, | |
| SkJSONWriter& writer, | |
| UrlDataManager& urlDataManager) { | |
| sk_sp<SkImage> image(bitmap.asImage()); | |
| writer.appendCString(DEBUGCANVAS_ATTRIBUTE_COLOR, color_type_name(bitmap.colorType())); | |
| writer.appendCString(DEBUGCANVAS_ATTRIBUTE_ALPHA, alpha_type_name(bitmap.alphaType())); | |
| // Image will appear to have no uses, TODO(nifong): provide the user with a useful explanation | |
| bool success = flatten(*image, writer, urlDataManager); | |
| return success; | |
| } | |
| static void apply_font_hinting(const SkFont& font, SkJSONWriter& writer) { | |
| SkFontHinting hinting = font.getHinting(); | |
| if (hinting != SkPaintDefaults_Hinting) { | |
| switch (hinting) { | |
| case SkFontHinting::kNone: | |
| writer.appendNString(DEBUGCANVAS_ATTRIBUTE_HINTING, DEBUGCANVAS_HINTING_NONE); | |
| break; | |
| case SkFontHinting::kSlight: | |
| writer.appendNString(DEBUGCANVAS_ATTRIBUTE_HINTING, DEBUGCANVAS_HINTING_SLIGHT); | |
| break; | |
| case SkFontHinting::kNormal: | |
| writer.appendNString(DEBUGCANVAS_ATTRIBUTE_HINTING, DEBUGCANVAS_HINTING_NORMAL); | |
| break; | |
| case SkFontHinting::kFull: | |
| writer.appendNString(DEBUGCANVAS_ATTRIBUTE_HINTING, DEBUGCANVAS_HINTING_FULL); | |
| break; | |
| } | |
| } | |
| } | |
| static void apply_font_edging(const SkFont& font, SkJSONWriter& writer) { | |
| switch (font.getEdging()) { | |
| case SkFont::Edging::kAlias: | |
| writer.appendNString(DEBUGCANVAS_ATTRIBUTE_EDGING, DEBUGCANVAS_EDGING_ALIAS); | |
| break; | |
| case SkFont::Edging::kAntiAlias: | |
| writer.appendNString(DEBUGCANVAS_ATTRIBUTE_EDGING, DEBUGCANVAS_EDGING_ANTIALIAS); | |
| break; | |
| case SkFont::Edging::kSubpixelAntiAlias: | |
| writer.appendNString(DEBUGCANVAS_ATTRIBUTE_EDGING, | |
| DEBUGCANVAS_EDGING_SUBPIXELANTIALIAS); | |
| break; | |
| } | |
| } | |
| static void apply_paint_color(const SkPaint& paint, SkJSONWriter& writer) { | |
| SkColor color = paint.getColor(); | |
| if (color != SK_ColorBLACK) { | |
| writer.appendName(DEBUGCANVAS_ATTRIBUTE_COLOR); | |
| DrawCommand::MakeJsonColor(writer, color); | |
| } | |
| } | |
| static void apply_paint_style(const SkPaint& paint, SkJSONWriter& writer) { | |
| SkPaint::Style style = paint.getStyle(); | |
| if (style != SkPaint::kFill_Style) { | |
| switch (style) { | |
| case SkPaint::kStroke_Style: { | |
| writer.appendNString(DEBUGCANVAS_ATTRIBUTE_STYLE, DEBUGCANVAS_STYLE_STROKE); | |
| break; | |
| } | |
| case SkPaint::kStrokeAndFill_Style: { | |
| writer.appendNString(DEBUGCANVAS_ATTRIBUTE_STYLE, DEBUGCANVAS_STYLE_STROKEANDFILL); | |
| break; | |
| } | |
| default: SkASSERT(false); | |
| } | |
| } | |
| } | |
| static void apply_paint_cap(const SkPaint& paint, SkJSONWriter& writer) { | |
| SkPaint::Cap cap = paint.getStrokeCap(); | |
| if (cap != SkPaint::kDefault_Cap) { | |
| switch (cap) { | |
| case SkPaint::kButt_Cap: | |
| writer.appendNString(DEBUGCANVAS_ATTRIBUTE_CAP, DEBUGCANVAS_CAP_BUTT); | |
| break; | |
| case SkPaint::kRound_Cap: | |
| writer.appendNString(DEBUGCANVAS_ATTRIBUTE_CAP, DEBUGCANVAS_CAP_ROUND); | |
| break; | |
| case SkPaint::kSquare_Cap: | |
| writer.appendNString(DEBUGCANVAS_ATTRIBUTE_CAP, DEBUGCANVAS_CAP_SQUARE); | |
| break; | |
| default: SkASSERT(false); | |
| } | |
| } | |
| } | |
| static void apply_paint_join(const SkPaint& paint, SkJSONWriter& writer) { | |
| SkPaint::Join join = paint.getStrokeJoin(); | |
| if (join != SkPaint::kDefault_Join) { | |
| switch (join) { | |
| case SkPaint::kMiter_Join: | |
| writer.appendNString(DEBUGCANVAS_ATTRIBUTE_STROKEJOIN, DEBUGCANVAS_MITER_JOIN); | |
| break; | |
| case SkPaint::kRound_Join: | |
| writer.appendNString(DEBUGCANVAS_ATTRIBUTE_STROKEJOIN, DEBUGCANVAS_ROUND_JOIN); | |
| break; | |
| case SkPaint::kBevel_Join: | |
| writer.appendNString(DEBUGCANVAS_ATTRIBUTE_STROKEJOIN, DEBUGCANVAS_BEVEL_JOIN); | |
| break; | |
| default: SkASSERT(false); | |
| } | |
| } | |
| } | |
| static void apply_paint_maskfilter(const SkPaint& paint, | |
| SkJSONWriter& writer, | |
| UrlDataManager& urlDataManager) { | |
| SkMaskFilter* maskFilter = paint.getMaskFilter(); | |
| if (maskFilter != nullptr) { | |
| SkMaskFilterBase::BlurRec blurRec; | |
| if (as_MFB(maskFilter)->asABlur(&blurRec)) { | |
| writer.beginObject(DEBUGCANVAS_ATTRIBUTE_BLUR); | |
| writer.appendFloat(DEBUGCANVAS_ATTRIBUTE_SIGMA, blurRec.fSigma); | |
| switch (blurRec.fStyle) { | |
| case SkBlurStyle::kNormal_SkBlurStyle: | |
| writer.appendNString(DEBUGCANVAS_ATTRIBUTE_STYLE, DEBUGCANVAS_BLURSTYLE_NORMAL); | |
| break; | |
| case SkBlurStyle::kSolid_SkBlurStyle: | |
| writer.appendNString(DEBUGCANVAS_ATTRIBUTE_STYLE, DEBUGCANVAS_BLURSTYLE_SOLID); | |
| break; | |
| case SkBlurStyle::kOuter_SkBlurStyle: | |
| writer.appendNString(DEBUGCANVAS_ATTRIBUTE_STYLE, DEBUGCANVAS_BLURSTYLE_OUTER); | |
| break; | |
| case SkBlurStyle::kInner_SkBlurStyle: | |
| writer.appendNString(DEBUGCANVAS_ATTRIBUTE_STYLE, DEBUGCANVAS_BLURSTYLE_INNER); | |
| break; | |
| default: SkASSERT(false); | |
| } | |
| writer.endObject(); // blur | |
| } else { | |
| writer.beginObject(DEBUGCANVAS_ATTRIBUTE_MASKFILTER); | |
| DrawCommand::flatten(maskFilter, writer, urlDataManager); | |
| writer.endObject(); // maskFilter | |
| } | |
| } | |
| } | |
| static void apply_paint_patheffect(const SkPaint& paint, | |
| SkJSONWriter& writer, | |
| UrlDataManager& urlDataManager) { | |
| SkPathEffect* pathEffect = paint.getPathEffect(); | |
| if (pathEffect != nullptr) { | |
| if (const auto dashInfo = as_PEB(pathEffect)->asADash()) { | |
| writer.beginObject(DEBUGCANVAS_ATTRIBUTE_DASHING); | |
| writer.beginArray(DEBUGCANVAS_ATTRIBUTE_INTERVALS, false); | |
| for (SkScalar value : dashInfo->fIntervals) { | |
| writer.appendFloat(value); | |
| } | |
| writer.endArray(); // intervals | |
| writer.appendFloat(DEBUGCANVAS_ATTRIBUTE_PHASE, dashInfo->fPhase); | |
| writer.endObject(); // dashing | |
| } else { | |
| writer.beginObject(DEBUGCANVAS_ATTRIBUTE_PATHEFFECT); | |
| DrawCommand::flatten(pathEffect, writer, urlDataManager); | |
| writer.endObject(); // pathEffect | |
| } | |
| } | |
| } | |
| static void apply_font_typeface(const SkFont& font, | |
| SkJSONWriter& writer, | |
| UrlDataManager& urlDataManager) { | |
| SkTypeface* typeface = font.getTypeface(); | |
| if (typeface != nullptr) { | |
| SkDynamicMemoryWStream buffer; | |
| if (!typeface->serialize(&buffer)) { | |
| return; | |
| } | |
| writer.beginObject(DEBUGCANVAS_ATTRIBUTE_TYPEFACE); | |
| sk_sp<SkData> data = buffer.detachAsData(); | |
| SkString url = encode_data(data, "application/octet-stream", urlDataManager); | |
| writer.appendString(DEBUGCANVAS_ATTRIBUTE_DATA, url); | |
| writer.endObject(); | |
| } | |
| } | |
| static void apply_flattenable(const char* key, | |
| SkFlattenable* flattenable, | |
| SkJSONWriter& writer, | |
| UrlDataManager& urlDataManager) { | |
| if (flattenable != nullptr) { | |
| writer.beginObject(key); | |
| DrawCommand::flatten(flattenable, writer, urlDataManager); | |
| writer.endObject(); | |
| } | |
| } | |
| void DrawCommand::MakeJsonPaint(SkJSONWriter& writer, | |
| const SkPaint& paint, | |
| UrlDataManager& urlDataManager) { | |
| writer.beginObject(); | |
| store_scalar(writer, DEBUGCANVAS_ATTRIBUTE_STROKEWIDTH, paint.getStrokeWidth(), 0.0f); | |
| store_scalar(writer, | |
| DEBUGCANVAS_ATTRIBUTE_STROKEMITER, | |
| paint.getStrokeMiter(), | |
| SkPaintDefaults_MiterLimit); | |
| store_bool(writer, DEBUGCANVAS_ATTRIBUTE_ANTIALIAS, paint.isAntiAlias(), false); | |
| store_bool(writer, DEBUGCANVAS_ATTRIBUTE_DITHER, paint.isDither(), false); | |
| apply_paint_color(paint, writer); | |
| apply_paint_style(paint, writer); | |
| apply_paint_blend_mode(paint, writer); | |
| apply_paint_cap(paint, writer); | |
| apply_paint_join(paint, writer); | |
| apply_paint_patheffect(paint, writer, urlDataManager); | |
| apply_paint_maskfilter(paint, writer, urlDataManager); | |
| apply_flattenable(DEBUGCANVAS_ATTRIBUTE_SHADER, paint.getShader(), writer, urlDataManager); | |
| apply_flattenable( | |
| DEBUGCANVAS_ATTRIBUTE_IMAGEFILTER, paint.getImageFilter(), writer, urlDataManager); | |
| apply_flattenable( | |
| DEBUGCANVAS_ATTRIBUTE_COLORFILTER, paint.getColorFilter(), writer, urlDataManager); | |
| writer.endObject(); // paint | |
| } | |
| static void MakeJsonFont(const SkFont& font, SkJSONWriter& writer, UrlDataManager& urlDataManager) { | |
| writer.beginObject(); | |
| store_bool(writer, DEBUGCANVAS_ATTRIBUTE_FAKEBOLDTEXT, font.isEmbolden(), false); | |
| store_bool(writer, DEBUGCANVAS_ATTRIBUTE_LINEARTEXT, font.isLinearMetrics(), false); | |
| store_bool(writer, DEBUGCANVAS_ATTRIBUTE_SUBPIXELTEXT, font.isSubpixel(), false); | |
| store_bool(writer, DEBUGCANVAS_ATTRIBUTE_EMBEDDEDBITMAPTEXT, font.isEmbeddedBitmaps(), false); | |
| store_bool(writer, DEBUGCANVAS_ATTRIBUTE_AUTOHINTING, font.isForceAutoHinting(), false); | |
| store_scalar(writer, DEBUGCANVAS_ATTRIBUTE_TEXTSIZE, font.getSize(), SkPaintDefaults_TextSize); | |
| store_scalar(writer, DEBUGCANVAS_ATTRIBUTE_TEXTSCALEX, font.getScaleX(), SK_Scalar1); | |
| store_scalar(writer, DEBUGCANVAS_ATTRIBUTE_TEXTSCALEX, font.getSkewX(), 0.0f); | |
| apply_font_edging(font, writer); | |
| apply_font_hinting(font, writer); | |
| apply_font_typeface(font, writer, urlDataManager); | |
| writer.endObject(); // font | |
| } | |
| void DrawCommand::MakeJsonLattice(SkJSONWriter& writer, const SkCanvas::Lattice& lattice) { | |
| writer.beginObject(); | |
| writer.appendS32(DEBUGCANVAS_ATTRIBUTE_LATTICEXCOUNT, lattice.fXCount); | |
| writer.appendS32(DEBUGCANVAS_ATTRIBUTE_LATTICEYCOUNT, lattice.fYCount); | |
| if (nullptr != lattice.fBounds) { | |
| writer.appendName(DEBUGCANVAS_ATTRIBUTE_BOUNDS); | |
| MakeJsonIRect(writer, *lattice.fBounds); | |
| } | |
| writer.beginArray(DEBUGCANVAS_ATTRIBUTE_LATTICEXDIVS); | |
| for (int i = 0; i < lattice.fXCount; i++) { | |
| writer.appendS32(lattice.fXDivs[i]); | |
| } | |
| writer.endArray(); // xdivs | |
| writer.beginArray(DEBUGCANVAS_ATTRIBUTE_LATTICEYDIVS); | |
| for (int i = 0; i < lattice.fYCount; i++) { | |
| writer.appendS32(lattice.fYDivs[i]); | |
| } | |
| writer.endArray(); // ydivs | |
| if (nullptr != lattice.fRectTypes) { | |
| writer.beginArray(DEBUGCANVAS_ATTRIBUTE_LATTICEFLAGS); | |
| int flagCount = 0; | |
| for (int row = 0; row < lattice.fYCount + 1; row++) { | |
| writer.beginArray(); | |
| for (int column = 0; column < lattice.fXCount + 1; column++) { | |
| writer.appendS32(lattice.fRectTypes[flagCount++]); | |
| } | |
| writer.endArray(); // row | |
| } | |
| writer.endArray(); | |
| } | |
| writer.endObject(); | |
| } | |
| ClearCommand::ClearCommand(SkColor color) : INHERITED(kClear_OpType) { fColor = color; } | |
| void ClearCommand::execute(SkCanvas* canvas) const { canvas->clear(fColor); } | |
| void ClearCommand::toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const { | |
| INHERITED::toJSON(writer, urlDataManager); | |
| writer.appendName(DEBUGCANVAS_ATTRIBUTE_COLOR); | |
| MakeJsonColor(writer, fColor); | |
| } | |
| ClipPathCommand::ClipPathCommand(const SkPath& path, SkClipOp op, bool doAA) | |
| : INHERITED(kClipPath_OpType) { | |
| fPath = path; | |
| fOp = op; | |
| fDoAA = doAA; | |
| } | |
| void ClipPathCommand::execute(SkCanvas* canvas) const { canvas->clipPath(fPath, fOp, fDoAA); } | |
| bool ClipPathCommand::render(SkCanvas* canvas) const { | |
| render_path(canvas, fPath); | |
| return true; | |
| } | |
| void ClipPathCommand::toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const { | |
| INHERITED::toJSON(writer, urlDataManager); | |
| writer.appendName(DEBUGCANVAS_ATTRIBUTE_PATH); | |
| MakeJsonPath(writer, fPath); | |
| writer.appendCString(DEBUGCANVAS_ATTRIBUTE_REGIONOP, clipop_name(fOp)); | |
| writer.appendBool(DEBUGCANVAS_ATTRIBUTE_ANTIALIAS, fDoAA); | |
| } | |
| ClipRegionCommand::ClipRegionCommand(const SkRegion& region, SkClipOp op) | |
| : INHERITED(kClipRegion_OpType) { | |
| fRegion = region; | |
| fOp = op; | |
| } | |
| void ClipRegionCommand::execute(SkCanvas* canvas) const { canvas->clipRegion(fRegion, fOp); } | |
| void ClipRegionCommand::toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const { | |
| INHERITED::toJSON(writer, urlDataManager); | |
| writer.appendName(DEBUGCANVAS_ATTRIBUTE_REGION); | |
| MakeJsonRegion(writer, fRegion); | |
| writer.appendCString(DEBUGCANVAS_ATTRIBUTE_REGIONOP, clipop_name(fOp)); | |
| } | |
| ClipRectCommand::ClipRectCommand(const SkRect& rect, SkClipOp op, bool doAA) | |
| : INHERITED(kClipRect_OpType) { | |
| fRect = rect; | |
| fOp = op; | |
| fDoAA = doAA; | |
| } | |
| void ClipRectCommand::execute(SkCanvas* canvas) const { canvas->clipRect(fRect, fOp, fDoAA); } | |
| void ClipRectCommand::toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const { | |
| INHERITED::toJSON(writer, urlDataManager); | |
| writer.appendName(DEBUGCANVAS_ATTRIBUTE_COORDS); | |
| MakeJsonRect(writer, fRect); | |
| writer.appendCString(DEBUGCANVAS_ATTRIBUTE_REGIONOP, clipop_name(fOp)); | |
| writer.appendBool(DEBUGCANVAS_ATTRIBUTE_ANTIALIAS, fDoAA); | |
| SkString desc; | |
| writer.appendString(DEBUGCANVAS_ATTRIBUTE_SHORTDESC, *str_append(&desc, fRect)); | |
| } | |
| ClipRRectCommand::ClipRRectCommand(const SkRRect& rrect, SkClipOp op, bool doAA) | |
| : INHERITED(kClipRRect_OpType) { | |
| fRRect = rrect; | |
| fOp = op; | |
| fDoAA = doAA; | |
| } | |
| void ClipRRectCommand::execute(SkCanvas* canvas) const { canvas->clipRRect(fRRect, fOp, fDoAA); } | |
| bool ClipRRectCommand::render(SkCanvas* canvas) const { | |
| render_rrect(canvas, fRRect); | |
| return true; | |
| } | |
| void ClipRRectCommand::toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const { | |
| INHERITED::toJSON(writer, urlDataManager); | |
| writer.appendName(DEBUGCANVAS_ATTRIBUTE_COORDS); | |
| make_json_rrect(writer, fRRect); | |
| writer.appendCString(DEBUGCANVAS_ATTRIBUTE_REGIONOP, clipop_name(fOp)); | |
| writer.appendBool(DEBUGCANVAS_ATTRIBUTE_ANTIALIAS, fDoAA); | |
| } | |
| ClipShaderCommand::ClipShaderCommand(sk_sp<SkShader> cs, SkClipOp op) | |
| : INHERITED(kClipShader_OpType) { | |
| fShader = std::move(cs); | |
| fOp = op; | |
| } | |
| void ClipShaderCommand::execute(SkCanvas* canvas) const { canvas->clipShader(fShader, fOp); } | |
| bool ClipShaderCommand::render(SkCanvas* canvas) const { | |
| SkPaint paint; | |
| paint.setShader(fShader); | |
| canvas->drawPaint(paint); | |
| return true; | |
| } | |
| void ClipShaderCommand::toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const { | |
| INHERITED::toJSON(writer, urlDataManager); | |
| apply_flattenable(DEBUGCANVAS_ATTRIBUTE_SHADER, fShader.get(), writer, urlDataManager); | |
| writer.appendCString(DEBUGCANVAS_ATTRIBUTE_REGIONOP, clipop_name(fOp)); | |
| } | |
| ResetClipCommand::ResetClipCommand() : INHERITED(kResetClip_OpType) {} | |
| void ResetClipCommand::execute(SkCanvas* canvas) const { SkCanvasPriv::ResetClip(canvas); } | |
| ConcatCommand::ConcatCommand(const SkMatrix& matrix) : INHERITED(kConcat_OpType) { | |
| fMatrix = matrix; | |
| } | |
| void ConcatCommand::execute(SkCanvas* canvas) const { canvas->concat(fMatrix); } | |
| namespace { | |
| void writeMatrixType(SkJSONWriter& writer, const SkMatrix& m) { | |
| switch (m.getType()) { | |
| case SkMatrix::kTranslate_Mask: | |
| writer.appendNString(DEBUGCANVAS_ATTRIBUTE_SHORTDESC, " (translate)"); | |
| break; | |
| case SkMatrix::kScale_Mask: | |
| writer.appendNString(DEBUGCANVAS_ATTRIBUTE_SHORTDESC, " (scale)"); | |
| break; | |
| case SkMatrix::kAffine_Mask: | |
| writer.appendNString(DEBUGCANVAS_ATTRIBUTE_SHORTDESC, " (rotation or skew)"); | |
| break; | |
| case SkMatrix::kPerspective_Mask: | |
| writer.appendNString(DEBUGCANVAS_ATTRIBUTE_SHORTDESC, " (perspective)"); | |
| break; | |
| default: | |
| break; | |
| } | |
| } | |
| } | |
| void ConcatCommand::toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const { | |
| INHERITED::toJSON(writer, urlDataManager); | |
| writer.appendName(DEBUGCANVAS_ATTRIBUTE_MATRIX); | |
| MakeJsonMatrix(writer, fMatrix); | |
| writeMatrixType(writer, fMatrix); | |
| } | |
| Concat44Command::Concat44Command(const SkM44& matrix) : INHERITED(kConcat44_OpType) { | |
| fMatrix = matrix; | |
| } | |
| void Concat44Command::execute(SkCanvas* canvas) const { canvas->concat(fMatrix); } | |
| void Concat44Command::toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const { | |
| INHERITED::toJSON(writer, urlDataManager); | |
| writer.appendName(DEBUGCANVAS_ATTRIBUTE_MATRIX); | |
| MakeJsonMatrix44(writer, fMatrix); | |
| } | |
| //// | |
| DrawAnnotationCommand::DrawAnnotationCommand(const SkRect& rect, | |
| const char key[], | |
| sk_sp<SkData> value) | |
| : INHERITED(kDrawAnnotation_OpType), fRect(rect), fKey(key), fValue(std::move(value)) {} | |
| void DrawAnnotationCommand::execute(SkCanvas* canvas) const { | |
| canvas->drawAnnotation(fRect, fKey.c_str(), fValue); | |
| } | |
| void DrawAnnotationCommand::toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const { | |
| INHERITED::toJSON(writer, urlDataManager); | |
| writer.appendName(DEBUGCANVAS_ATTRIBUTE_COORDS); | |
| MakeJsonRect(writer, fRect); | |
| writer.appendString("key", fKey); | |
| if (fValue) { | |
| writer.appendString("value", static_cast<const char*>(fValue->data()), fValue->size()); | |
| } | |
| SkString desc; | |
| str_append(&desc, fRect)->appendf(" %s", fKey.c_str()); | |
| writer.appendString(DEBUGCANVAS_ATTRIBUTE_SHORTDESC, desc); | |
| } | |
| //// | |
| template <typename T> void assign_if_not_null(std::optional<T>& object, const T* pointer) { | |
| if (pointer) { | |
| object = *pointer; | |
| } | |
| } | |
| DrawImageCommand::DrawImageCommand(const SkImage* image, | |
| SkScalar left, | |
| SkScalar top, | |
| const SkSamplingOptions& sampling, | |
| const SkPaint* paint) | |
| : INHERITED(kDrawImage_OpType) | |
| , fImage(SkRef(image)) | |
| , fLeft(left) | |
| , fTop(top) | |
| , fSampling(sampling) { | |
| assign_if_not_null(fPaint, paint); | |
| } | |
| void DrawImageCommand::execute(SkCanvas* canvas) const { | |
| canvas->drawImage(fImage.get(), fLeft, fTop, fSampling, SkOptAddressOrNull(fPaint)); | |
| } | |
| bool DrawImageCommand::render(SkCanvas* canvas) const { | |
| SkAutoCanvasRestore acr(canvas, true); | |
| canvas->clear(0xFFFFFFFF); | |
| xlate_and_scale_to_bounds( | |
| canvas, | |
| SkRect::MakeXYWH( | |
| fLeft, fTop, SkIntToScalar(fImage->width()), SkIntToScalar(fImage->height()))); | |
| this->execute(canvas); | |
| return true; | |
| } | |
| uint64_t DrawImageCommand::imageId(UrlDataManager& udm) const { | |
| return udm.lookupImage(fImage.get()); | |
| } | |
| void DrawImageCommand::toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const { | |
| INHERITED::toJSON(writer, urlDataManager); | |
| flatten(*fImage, writer, urlDataManager); | |
| writer.appendName(DEBUGCANVAS_ATTRIBUTE_COORDS); | |
| MakeJsonPoint(writer, fLeft, fTop); | |
| if (fPaint.has_value()) { | |
| writer.appendName(DEBUGCANVAS_ATTRIBUTE_PAINT); | |
| MakeJsonPaint(writer, *fPaint, urlDataManager); | |
| } | |
| writer.appendName(DEBUGCANVAS_ATTRIBUTE_SAMPLING); | |
| MakeJsonSampling(writer, fSampling); | |
| writer.appendU32(DEBUGCANVAS_ATTRIBUTE_UNIQUE_ID, fImage->uniqueID()); | |
| writer.appendS32(DEBUGCANVAS_ATTRIBUTE_WIDTH, fImage->width()); | |
| writer.appendS32(DEBUGCANVAS_ATTRIBUTE_HEIGHT, fImage->height()); | |
| switch (fImage->alphaType()) { | |
| case kOpaque_SkAlphaType: | |
| writer.appendNString(DEBUGCANVAS_ATTRIBUTE_ALPHA, DEBUGCANVAS_ALPHATYPE_OPAQUE); | |
| break; | |
| case kPremul_SkAlphaType: | |
| writer.appendNString(DEBUGCANVAS_ATTRIBUTE_ALPHA, DEBUGCANVAS_ALPHATYPE_PREMUL); | |
| break; | |
| case kUnpremul_SkAlphaType: | |
| writer.appendNString(DEBUGCANVAS_ATTRIBUTE_ALPHA, DEBUGCANVAS_ALPHATYPE_UNPREMUL); | |
| break; | |
| default: | |
| writer.appendNString(DEBUGCANVAS_ATTRIBUTE_ALPHA, DEBUGCANVAS_ALPHATYPE_UNKNOWN); | |
| break; | |
| } | |
| } | |
| DrawImageLatticeCommand::DrawImageLatticeCommand(const SkImage* image, | |
| const SkCanvas::Lattice& lattice, | |
| const SkRect& dst, | |
| SkFilterMode filter, | |
| const SkPaint* paint) | |
| : INHERITED(kDrawImageLattice_OpType) | |
| , fImage(SkRef(image)) | |
| , fLattice(lattice) | |
| , fDst(dst) | |
| , fFilter(filter) { | |
| assign_if_not_null(fPaint, paint); | |
| } | |
| void DrawImageLatticeCommand::execute(SkCanvas* canvas) const { | |
| canvas->drawImageLattice(fImage.get(), fLattice, fDst, fFilter, SkOptAddressOrNull(fPaint)); | |
| } | |
| bool DrawImageLatticeCommand::render(SkCanvas* canvas) const { | |
| SkAutoCanvasRestore acr(canvas, true); | |
| canvas->clear(0xFFFFFFFF); | |
| xlate_and_scale_to_bounds(canvas, fDst); | |
| this->execute(canvas); | |
| return true; | |
| } | |
| uint64_t DrawImageLatticeCommand::imageId(UrlDataManager& udm) const { | |
| return udm.lookupImage(fImage.get()); | |
| } | |
| void DrawImageLatticeCommand::toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const { | |
| INHERITED::toJSON(writer, urlDataManager); | |
| flatten(*fImage, writer, urlDataManager); | |
| writer.appendName(DEBUGCANVAS_ATTRIBUTE_LATTICE); | |
| MakeJsonLattice(writer, fLattice); | |
| writer.appendName(DEBUGCANVAS_ATTRIBUTE_DST); | |
| MakeJsonRect(writer, fDst); | |
| if (fPaint.has_value()) { | |
| writer.appendName(DEBUGCANVAS_ATTRIBUTE_PAINT); | |
| MakeJsonPaint(writer, *fPaint, urlDataManager); | |
| } | |
| SkString desc; | |
| writer.appendString(DEBUGCANVAS_ATTRIBUTE_SHORTDESC, *str_append(&desc, fDst)); | |
| } | |
| DrawImageRectCommand::DrawImageRectCommand(const SkImage* image, | |
| const SkRect& src, | |
| const SkRect& dst, | |
| const SkSamplingOptions& sampling, | |
| const SkPaint* paint, | |
| SkCanvas::SrcRectConstraint constraint) | |
| : INHERITED(kDrawImageRect_OpType) | |
| , fImage(SkRef(image)) | |
| , fSrc(src) | |
| , fDst(dst) | |
| , fSampling(sampling) | |
| , fConstraint(constraint) { | |
| assign_if_not_null(fPaint, paint); | |
| } | |
| void DrawImageRectCommand::execute(SkCanvas* canvas) const { | |
| canvas->drawImageRect(fImage.get(), fSrc, fDst, fSampling, | |
| SkOptAddressOrNull(fPaint), fConstraint); | |
| } | |
| bool DrawImageRectCommand::render(SkCanvas* canvas) const { | |
| SkAutoCanvasRestore acr(canvas, true); | |
| canvas->clear(0xFFFFFFFF); | |
| xlate_and_scale_to_bounds(canvas, fDst); | |
| this->execute(canvas); | |
| return true; | |
| } | |
| uint64_t DrawImageRectCommand::imageId(UrlDataManager& udm) const { | |
| return udm.lookupImage(fImage.get()); | |
| } | |
| void DrawImageRectCommand::toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const { | |
| INHERITED::toJSON(writer, urlDataManager); | |
| flatten(*fImage, writer, urlDataManager); | |
| writer.appendName(DEBUGCANVAS_ATTRIBUTE_SRC); | |
| MakeJsonRect(writer, fSrc); | |
| writer.appendName(DEBUGCANVAS_ATTRIBUTE_DST); | |
| MakeJsonRect(writer, fDst); | |
| writer.appendName(DEBUGCANVAS_ATTRIBUTE_SAMPLING); | |
| MakeJsonSampling(writer, fSampling); | |
| if (fPaint.has_value()) { | |
| writer.appendName(DEBUGCANVAS_ATTRIBUTE_PAINT); | |
| MakeJsonPaint(writer, *fPaint, urlDataManager); | |
| } | |
| if (fConstraint == SkCanvas::kStrict_SrcRectConstraint) { | |
| writer.appendBool(DEBUGCANVAS_ATTRIBUTE_STRICT, true); | |
| } | |
| SkString desc; | |
| writer.appendString(DEBUGCANVAS_ATTRIBUTE_SHORTDESC, *str_append(&desc, fDst)); | |
| } | |
| DrawImageRectLayerCommand::DrawImageRectLayerCommand(DebugLayerManager* layerManager, | |
| const int nodeId, | |
| const int frame, | |
| const SkRect& src, | |
| const SkRect& dst, | |
| const SkSamplingOptions& sampling, | |
| const SkPaint* paint, | |
| SkCanvas::SrcRectConstraint constraint) | |
| : INHERITED(kDrawImageRectLayer_OpType) | |
| , fLayerManager(layerManager) | |
| , fNodeId(nodeId) | |
| , fFrame(frame) | |
| , fSrc(src) | |
| , fDst(dst) | |
| , fSampling(sampling) | |
| , fConstraint(constraint) { | |
| assign_if_not_null(fPaint, paint); | |
| } | |
| void DrawImageRectLayerCommand::execute(SkCanvas* canvas) const { | |
| sk_sp<SkImage> snapshot = fLayerManager->getLayerAsImage(fNodeId, fFrame); | |
| canvas->drawImageRect(snapshot.get(), fSrc, fDst, SkSamplingOptions(), | |
| SkOptAddressOrNull(fPaint), fConstraint); | |
| } | |
| bool DrawImageRectLayerCommand::render(SkCanvas* canvas) const { | |
| SkAutoCanvasRestore acr(canvas, true); | |
| canvas->clear(0xFFFFFFFF); | |
| xlate_and_scale_to_bounds(canvas, fDst); | |
| this->execute(canvas); | |
| return true; | |
| } | |
| void DrawImageRectLayerCommand::toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const { | |
| INHERITED::toJSON(writer, urlDataManager); | |
| // Don't append an image attribute here, the image can be rendered in as many different ways | |
| // as there are commands in the layer, at least. the urlDataManager would save each one under | |
| // a different URL. | |
| // Append the node id, and the layer inspector of the debugger will know what to do with it. | |
| writer.appendS64(DEBUGCANVAS_ATTRIBUTE_LAYERNODEID, fNodeId); | |
| writer.appendName(DEBUGCANVAS_ATTRIBUTE_SRC); | |
| MakeJsonRect(writer, fSrc); | |
| writer.appendName(DEBUGCANVAS_ATTRIBUTE_DST); | |
| MakeJsonRect(writer, fDst); | |
| writer.appendName(DEBUGCANVAS_ATTRIBUTE_SAMPLING); | |
| MakeJsonSampling(writer, fSampling); | |
| if (fPaint.has_value()) { | |
| writer.appendName(DEBUGCANVAS_ATTRIBUTE_PAINT); | |
| MakeJsonPaint(writer, *fPaint, urlDataManager); | |
| } | |
| if (fConstraint == SkCanvas::kStrict_SrcRectConstraint) { | |
| writer.appendBool(DEBUGCANVAS_ATTRIBUTE_STRICT, true); | |
| } | |
| SkString desc; | |
| writer.appendString(DEBUGCANVAS_ATTRIBUTE_SHORTDESC, *str_append(&desc, fDst)); | |
| } | |
| DrawOvalCommand::DrawOvalCommand(const SkRect& oval, const SkPaint& paint) | |
| : INHERITED(kDrawOval_OpType) { | |
| fOval = oval; | |
| fPaint = paint; | |
| } | |
| void DrawOvalCommand::execute(SkCanvas* canvas) const { canvas->drawOval(fOval, fPaint); } | |
| bool DrawOvalCommand::render(SkCanvas* canvas) const { | |
| canvas->clear(0xFFFFFFFF); | |
| canvas->save(); | |
| xlate_and_scale_to_bounds(canvas, fOval); | |
| SkPaint p; | |
| p.setColor(SK_ColorBLACK); | |
| p.setStyle(SkPaint::kStroke_Style); | |
| canvas->drawOval(fOval, p); | |
| canvas->restore(); | |
| return true; | |
| } | |
| void DrawOvalCommand::toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const { | |
| INHERITED::toJSON(writer, urlDataManager); | |
| writer.appendName(DEBUGCANVAS_ATTRIBUTE_COORDS); | |
| MakeJsonRect(writer, fOval); | |
| writer.appendName(DEBUGCANVAS_ATTRIBUTE_PAINT); | |
| MakeJsonPaint(writer, fPaint, urlDataManager); | |
| } | |
| DrawArcCommand::DrawArcCommand(const SkRect& oval, | |
| SkScalar startAngle, | |
| SkScalar sweepAngle, | |
| bool useCenter, | |
| const SkPaint& paint) | |
| : INHERITED(kDrawArc_OpType) { | |
| fOval = oval; | |
| fStartAngle = startAngle; | |
| fSweepAngle = sweepAngle; | |
| fUseCenter = useCenter; | |
| fPaint = paint; | |
| } | |
| void DrawArcCommand::execute(SkCanvas* canvas) const { | |
| canvas->drawArc(fOval, fStartAngle, fSweepAngle, fUseCenter, fPaint); | |
| } | |
| bool DrawArcCommand::render(SkCanvas* canvas) const { | |
| canvas->clear(0xFFFFFFFF); | |
| canvas->save(); | |
| xlate_and_scale_to_bounds(canvas, fOval); | |
| SkPaint p; | |
| p.setColor(SK_ColorBLACK); | |
| p.setStyle(SkPaint::kStroke_Style); | |
| canvas->drawArc(fOval, fStartAngle, fSweepAngle, fUseCenter, p); | |
| canvas->restore(); | |
| return true; | |
| } | |
| void DrawArcCommand::toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const { | |
| INHERITED::toJSON(writer, urlDataManager); | |
| writer.appendName(DEBUGCANVAS_ATTRIBUTE_COORDS); | |
| MakeJsonRect(writer, fOval); | |
| writer.appendFloat(DEBUGCANVAS_ATTRIBUTE_STARTANGLE, fStartAngle); | |
| writer.appendFloat(DEBUGCANVAS_ATTRIBUTE_SWEEPANGLE, fSweepAngle); | |
| writer.appendBool(DEBUGCANVAS_ATTRIBUTE_USECENTER, fUseCenter); | |
| writer.appendName(DEBUGCANVAS_ATTRIBUTE_PAINT); | |
| MakeJsonPaint(writer, fPaint, urlDataManager); | |
| } | |
| DrawPaintCommand::DrawPaintCommand(const SkPaint& paint) : INHERITED(kDrawPaint_OpType) { | |
| fPaint = paint; | |
| } | |
| void DrawPaintCommand::execute(SkCanvas* canvas) const { canvas->drawPaint(fPaint); } | |
| bool DrawPaintCommand::render(SkCanvas* canvas) const { | |
| canvas->clear(0xFFFFFFFF); | |
| canvas->drawPaint(fPaint); | |
| return true; | |
| } | |
| void DrawPaintCommand::toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const { | |
| INHERITED::toJSON(writer, urlDataManager); | |
| writer.appendName(DEBUGCANVAS_ATTRIBUTE_PAINT); | |
| MakeJsonPaint(writer, fPaint, urlDataManager); | |
| } | |
| DrawBehindCommand::DrawBehindCommand(const SkPaint& paint) : INHERITED(kDrawPaint_OpType) { | |
| fPaint = paint; | |
| } | |
| void DrawBehindCommand::execute(SkCanvas* canvas) const { | |
| SkCanvasPriv::DrawBehind(canvas, fPaint); | |
| } | |
| bool DrawBehindCommand::render(SkCanvas* canvas) const { | |
| canvas->clear(0xFFFFFFFF); | |
| SkCanvasPriv::DrawBehind(canvas, fPaint); | |
| return true; | |
| } | |
| void DrawBehindCommand::toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const { | |
| INHERITED::toJSON(writer, urlDataManager); | |
| writer.appendName(DEBUGCANVAS_ATTRIBUTE_PAINT); | |
| MakeJsonPaint(writer, fPaint, urlDataManager); | |
| } | |
| DrawPathCommand::DrawPathCommand(const SkPath& path, const SkPaint& paint) | |
| : INHERITED(kDrawPath_OpType) { | |
| fPath = path; | |
| fPaint = paint; | |
| } | |
| void DrawPathCommand::execute(SkCanvas* canvas) const { canvas->drawPath(fPath, fPaint); } | |
| bool DrawPathCommand::render(SkCanvas* canvas) const { | |
| render_path(canvas, fPath); | |
| return true; | |
| } | |
| void DrawPathCommand::toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const { | |
| INHERITED::toJSON(writer, urlDataManager); | |
| writer.appendName(DEBUGCANVAS_ATTRIBUTE_PATH); | |
| MakeJsonPath(writer, fPath); | |
| writer.appendName(DEBUGCANVAS_ATTRIBUTE_PAINT); | |
| MakeJsonPaint(writer, fPaint, urlDataManager); | |
| } | |
| DrawRegionCommand::DrawRegionCommand(const SkRegion& region, const SkPaint& paint) | |
| : INHERITED(kDrawRegion_OpType) { | |
| fRegion = region; | |
| fPaint = paint; | |
| } | |
| void DrawRegionCommand::execute(SkCanvas* canvas) const { canvas->drawRegion(fRegion, fPaint); } | |
| bool DrawRegionCommand::render(SkCanvas* canvas) const { | |
| render_region(canvas, fRegion); | |
| return true; | |
| } | |
| void DrawRegionCommand::toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const { | |
| INHERITED::toJSON(writer, urlDataManager); | |
| writer.appendName(DEBUGCANVAS_ATTRIBUTE_REGION); | |
| MakeJsonRegion(writer, fRegion); | |
| writer.appendName(DEBUGCANVAS_ATTRIBUTE_PAINT); | |
| MakeJsonPaint(writer, fPaint, urlDataManager); | |
| } | |
| BeginDrawPictureCommand::BeginDrawPictureCommand(const SkPicture* picture, | |
| const SkMatrix* matrix, | |
| const SkPaint* paint) | |
| : INHERITED(kBeginDrawPicture_OpType) | |
| , fPicture(SkRef(picture)) { | |
| assign_if_not_null(fMatrix, matrix); | |
| assign_if_not_null(fPaint, paint); | |
| } | |
| void BeginDrawPictureCommand::execute(SkCanvas* canvas) const { | |
| if (fPaint.has_value()) { | |
| SkRect bounds = fPicture->cullRect(); | |
| if (fMatrix.has_value()) { | |
| fMatrix->mapRect(&bounds); | |
| } | |
| canvas->saveLayer(&bounds, &fPaint.value()); | |
| } | |
| if (fMatrix.has_value()) { | |
| if (!fPaint.has_value()) { | |
| canvas->save(); | |
| } | |
| canvas->concat(*fMatrix); | |
| } | |
| } | |
| bool BeginDrawPictureCommand::render(SkCanvas* canvas) const { | |
| canvas->clear(0xFFFFFFFF); | |
| canvas->save(); | |
| xlate_and_scale_to_bounds(canvas, fPicture->cullRect()); | |
| canvas->drawPicture(fPicture.get()); | |
| canvas->restore(); | |
| return true; | |
| } | |
| EndDrawPictureCommand::EndDrawPictureCommand(bool restore) | |
| : INHERITED(kEndDrawPicture_OpType), fRestore(restore) {} | |
| void EndDrawPictureCommand::execute(SkCanvas* canvas) const { | |
| if (fRestore) { | |
| canvas->restore(); | |
| } | |
| } | |
| DrawPointsCommand::DrawPointsCommand(SkCanvas::PointMode mode, | |
| size_t count, | |
| const SkPoint pts[], | |
| const SkPaint& paint) | |
| : INHERITED(kDrawPoints_OpType), fMode(mode), fPts(pts, count), fPaint(paint) {} | |
| void DrawPointsCommand::execute(SkCanvas* canvas) const { | |
| canvas->drawPoints(fMode, fPts, fPaint); | |
| } | |
| bool DrawPointsCommand::render(SkCanvas* canvas) const { | |
| canvas->clear(0xFFFFFFFF); | |
| canvas->save(); | |
| SkRect bounds; | |
| bounds.setEmpty(); | |
| for (int i = 0; i < fPts.size(); ++i) { | |
| SkRectPriv::GrowToInclude(&bounds, fPts[i]); | |
| } | |
| xlate_and_scale_to_bounds(canvas, bounds); | |
| SkPaint p; | |
| p.setColor(SK_ColorBLACK); | |
| p.setStyle(SkPaint::kStroke_Style); | |
| canvas->drawPoints(fMode, fPts, p); | |
| canvas->restore(); | |
| return true; | |
| } | |
| void DrawPointsCommand::toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const { | |
| INHERITED::toJSON(writer, urlDataManager); | |
| writer.appendCString(DEBUGCANVAS_ATTRIBUTE_MODE, pointmode_name(fMode)); | |
| writer.beginArray(DEBUGCANVAS_ATTRIBUTE_POINTS); | |
| for (int i = 0; i < fPts.size(); i++) { | |
| MakeJsonPoint(writer, fPts[i]); | |
| } | |
| writer.endArray(); // points | |
| writer.appendName(DEBUGCANVAS_ATTRIBUTE_PAINT); | |
| MakeJsonPaint(writer, fPaint, urlDataManager); | |
| } | |
| DrawTextBlobCommand::DrawTextBlobCommand(sk_sp<SkTextBlob> blob, | |
| SkScalar x, | |
| SkScalar y, | |
| const SkPaint& paint) | |
| : INHERITED(kDrawTextBlob_OpType) | |
| , fBlob(std::move(blob)) | |
| , fXPos(x) | |
| , fYPos(y) | |
| , fPaint(paint) {} | |
| void DrawTextBlobCommand::execute(SkCanvas* canvas) const { | |
| canvas->drawTextBlob(fBlob, fXPos, fYPos, fPaint); | |
| } | |
| bool DrawTextBlobCommand::render(SkCanvas* canvas) const { | |
| canvas->clear(SK_ColorWHITE); | |
| canvas->save(); | |
| SkRect bounds = fBlob->bounds().makeOffset(fXPos, fYPos); | |
| xlate_and_scale_to_bounds(canvas, bounds); | |
| canvas->drawTextBlob(fBlob, fXPos, fYPos, fPaint); | |
| canvas->restore(); | |
| return true; | |
| } | |
| void DrawTextBlobCommand::toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const { | |
| INHERITED::toJSON(writer, urlDataManager); | |
| writer.appendFloat(DEBUGCANVAS_ATTRIBUTE_X, fXPos); | |
| writer.appendFloat(DEBUGCANVAS_ATTRIBUTE_Y, fYPos); | |
| SkRect bounds = fBlob->bounds(); | |
| writer.appendName(DEBUGCANVAS_ATTRIBUTE_BOUNDS); | |
| MakeJsonRect(writer, bounds); | |
| writer.appendName(DEBUGCANVAS_ATTRIBUTE_PAINT); | |
| MakeJsonPaint(writer, fPaint, urlDataManager); | |
| writer.beginArray(DEBUGCANVAS_ATTRIBUTE_RUNS); | |
| SkTextBlobRunIterator iter(fBlob.get()); | |
| while (!iter.done()) { | |
| writer.beginObject(); // run | |
| if (iter.textSize()) { | |
| writer.appendString(DEBUGCANVAS_ATTRIBUTE_TEXT, iter.text(), iter.textSize()); | |
| } | |
| writer.appendName(DEBUGCANVAS_ATTRIBUTE_FONT); | |
| MakeJsonFont(iter.font(), writer, urlDataManager); | |
| writer.appendName(DEBUGCANVAS_ATTRIBUTE_COORDS); | |
| MakeJsonPoint(writer, iter.offset()); | |
| writer.beginArray(DEBUGCANVAS_ATTRIBUTE_GLYPHS); | |
| for (uint32_t i = 0; i < iter.glyphCount(); i++) { | |
| writer.appendU32(iter.glyphs()[i]); | |
| } | |
| writer.endArray(); // glyphs | |
| if (iter.positioning() != SkTextBlobRunIterator::kDefault_Positioning) { | |
| writer.beginArray(DEBUGCANVAS_ATTRIBUTE_POSITIONS); | |
| const SkScalar* iterPositions = iter.pos(); | |
| for (uint32_t i = 0; i < iter.glyphCount(); i++) { | |
| switch (iter.positioning()) { | |
| case SkTextBlobRunIterator::kFull_Positioning: | |
| MakeJsonPoint(writer, iterPositions[i * 2], iterPositions[i * 2 + 1]); | |
| break; | |
| case SkTextBlobRunIterator::kHorizontal_Positioning: | |
| writer.appendFloat(iterPositions[i]); | |
| break; | |
| case SkTextBlobRunIterator::kDefault_Positioning: break; | |
| case SkTextBlobRunIterator::kRSXform_Positioning: | |
| // TODO_RSXFORM_BLOB | |
| break; | |
| } | |
| } | |
| writer.endArray(); // positions | |
| } | |
| if (iter.clusters()) { | |
| writer.beginArray(DEBUGCANVAS_ATTRIBUTE_CLUSTERS); | |
| for (uint32_t i = 0; i < iter.glyphCount(); i++) { | |
| writer.appendU32(iter.clusters()[i]); | |
| } | |
| writer.endArray(); // clusters | |
| } | |
| writer.endObject(); // run | |
| iter.next(); | |
| } | |
| writer.endArray(); // runs | |
| SkString desc; | |
| // make the bounds local by applying the x,y | |
| bounds.offset(fXPos, fYPos); | |
| writer.appendString(DEBUGCANVAS_ATTRIBUTE_SHORTDESC, *str_append(&desc, bounds)); | |
| } | |
| DrawPatchCommand::DrawPatchCommand(const SkPoint cubics[12], | |
| const SkColor colors[4], | |
| const SkPoint texCoords[4], | |
| SkBlendMode bmode, | |
| const SkPaint& paint) | |
| : INHERITED(kDrawPatch_OpType), fBlendMode(bmode) { | |
| memcpy(fCubics, cubics, sizeof(fCubics)); | |
| if (colors != nullptr) { | |
| memcpy(fColors, colors, sizeof(fColors)); | |
| fColorsPtr = fColors; | |
| } else { | |
| fColorsPtr = nullptr; | |
| } | |
| if (texCoords != nullptr) { | |
| memcpy(fTexCoords, texCoords, sizeof(fTexCoords)); | |
| fTexCoordsPtr = fTexCoords; | |
| } else { | |
| fTexCoordsPtr = nullptr; | |
| } | |
| fPaint = paint; | |
| } | |
| void DrawPatchCommand::execute(SkCanvas* canvas) const { | |
| canvas->drawPatch(fCubics, fColorsPtr, fTexCoordsPtr, fBlendMode, fPaint); | |
| } | |
| void DrawPatchCommand::toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const { | |
| INHERITED::toJSON(writer, urlDataManager); | |
| writer.beginArray(DEBUGCANVAS_ATTRIBUTE_CUBICS); | |
| for (int i = 0; i < 12; i++) { | |
| MakeJsonPoint(writer, fCubics[i]); | |
| } | |
| writer.endArray(); // cubics | |
| if (fColorsPtr != nullptr) { | |
| writer.beginArray(DEBUGCANVAS_ATTRIBUTE_COLORS); | |
| for (int i = 0; i < 4; i++) { | |
| MakeJsonColor(writer, fColorsPtr[i]); | |
| } | |
| writer.endArray(); // colors | |
| } | |
| if (fTexCoordsPtr != nullptr) { | |
| writer.beginArray(DEBUGCANVAS_ATTRIBUTE_TEXTURECOORDS); | |
| for (int i = 0; i < 4; i++) { | |
| MakeJsonPoint(writer, fTexCoords[i]); | |
| } | |
| writer.endArray(); // texCoords | |
| } | |
| // fBlendMode | |
| } | |
| DrawRectCommand::DrawRectCommand(const SkRect& rect, const SkPaint& paint) | |
| : INHERITED(kDrawRect_OpType) { | |
| fRect = rect; | |
| fPaint = paint; | |
| } | |
| void DrawRectCommand::execute(SkCanvas* canvas) const { canvas->drawRect(fRect, fPaint); } | |
| void DrawRectCommand::toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const { | |
| INHERITED::toJSON(writer, urlDataManager); | |
| writer.appendName(DEBUGCANVAS_ATTRIBUTE_COORDS); | |
| MakeJsonRect(writer, fRect); | |
| writer.appendName(DEBUGCANVAS_ATTRIBUTE_PAINT); | |
| MakeJsonPaint(writer, fPaint, urlDataManager); | |
| SkString desc; | |
| writer.appendString(DEBUGCANVAS_ATTRIBUTE_SHORTDESC, *str_append(&desc, fRect)); | |
| } | |
| DrawRRectCommand::DrawRRectCommand(const SkRRect& rrect, const SkPaint& paint) | |
| : INHERITED(kDrawRRect_OpType) { | |
| fRRect = rrect; | |
| fPaint = paint; | |
| } | |
| void DrawRRectCommand::execute(SkCanvas* canvas) const { canvas->drawRRect(fRRect, fPaint); } | |
| bool DrawRRectCommand::render(SkCanvas* canvas) const { | |
| render_rrect(canvas, fRRect); | |
| return true; | |
| } | |
| void DrawRRectCommand::toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const { | |
| INHERITED::toJSON(writer, urlDataManager); | |
| writer.appendName(DEBUGCANVAS_ATTRIBUTE_COORDS); | |
| make_json_rrect(writer, fRRect); | |
| writer.appendName(DEBUGCANVAS_ATTRIBUTE_PAINT); | |
| MakeJsonPaint(writer, fPaint, urlDataManager); | |
| } | |
| DrawDRRectCommand::DrawDRRectCommand(const SkRRect& outer, | |
| const SkRRect& inner, | |
| const SkPaint& paint) | |
| : INHERITED(kDrawDRRect_OpType) { | |
| fOuter = outer; | |
| fInner = inner; | |
| fPaint = paint; | |
| } | |
| void DrawDRRectCommand::execute(SkCanvas* canvas) const { | |
| canvas->drawDRRect(fOuter, fInner, fPaint); | |
| } | |
| bool DrawDRRectCommand::render(SkCanvas* canvas) const { | |
| render_drrect(canvas, fOuter, fInner); | |
| return true; | |
| } | |
| void DrawDRRectCommand::toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const { | |
| INHERITED::toJSON(writer, urlDataManager); | |
| writer.appendName(DEBUGCANVAS_ATTRIBUTE_OUTER); | |
| make_json_rrect(writer, fOuter); | |
| writer.appendName(DEBUGCANVAS_ATTRIBUTE_INNER); | |
| make_json_rrect(writer, fInner); | |
| writer.appendName(DEBUGCANVAS_ATTRIBUTE_PAINT); | |
| MakeJsonPaint(writer, fPaint, urlDataManager); | |
| } | |
| DrawShadowCommand::DrawShadowCommand(const SkPath& path, const SkDrawShadowRec& rec) | |
| : INHERITED(kDrawShadow_OpType) { | |
| fPath = path; | |
| fShadowRec = rec; | |
| } | |
| void DrawShadowCommand::execute(SkCanvas* canvas) const { | |
| canvas->private_draw_shadow_rec(fPath, fShadowRec); | |
| } | |
| bool DrawShadowCommand::render(SkCanvas* canvas) const { | |
| render_shadow(canvas, fPath, fShadowRec); | |
| return true; | |
| } | |
| void DrawShadowCommand::toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const { | |
| INHERITED::toJSON(writer, urlDataManager); | |
| bool geometricOnly = SkToBool(fShadowRec.fFlags & SkShadowFlags::kGeometricOnly_ShadowFlag); | |
| bool transparentOccluder = | |
| SkToBool(fShadowRec.fFlags & SkShadowFlags::kTransparentOccluder_ShadowFlag); | |
| writer.appendName(DEBUGCANVAS_ATTRIBUTE_PATH); | |
| MakeJsonPath(writer, fPath); | |
| writer.appendName(DEBUGCANVAS_ATTRIBUTE_ZPLANE); | |
| MakeJsonPoint3(writer, fShadowRec.fZPlaneParams); | |
| writer.appendName(DEBUGCANVAS_ATTRIBUTE_LIGHTPOSITION); | |
| MakeJsonPoint3(writer, fShadowRec.fLightPos); | |
| writer.appendFloat(DEBUGCANVAS_ATTRIBUTE_LIGHTRADIUS, fShadowRec.fLightRadius); | |
| writer.appendName(DEBUGCANVAS_ATTRIBUTE_AMBIENTCOLOR); | |
| MakeJsonColor(writer, fShadowRec.fAmbientColor); | |
| writer.appendName(DEBUGCANVAS_ATTRIBUTE_SPOTCOLOR); | |
| MakeJsonColor(writer, fShadowRec.fSpotColor); | |
| store_bool(writer, DEBUGCANVAS_SHADOWFLAG_TRANSPARENT_OCC, transparentOccluder, false); | |
| store_bool(writer, DEBUGCANVAS_SHADOWFLAG_GEOMETRIC_ONLY, geometricOnly, false); | |
| } | |
| /////////////////////////////////////////////////////////////////////////////////////////////////// | |
| DrawEdgeAAQuadCommand::DrawEdgeAAQuadCommand(const SkRect& rect, | |
| const SkPoint clip[4], | |
| SkCanvas::QuadAAFlags aa, | |
| const SkColor4f& color, | |
| SkBlendMode mode) | |
| : INHERITED(kDrawEdgeAAQuad_OpType) | |
| , fRect(rect) | |
| , fHasClip(clip != nullptr) | |
| , fAA(aa) | |
| , fColor(color) | |
| , fMode(mode) { | |
| if (clip) { | |
| for (int i = 0; i < 4; ++i) { | |
| fClip[i] = clip[i]; | |
| } | |
| } | |
| } | |
| void DrawEdgeAAQuadCommand::execute(SkCanvas* canvas) const { | |
| canvas->experimental_DrawEdgeAAQuad(fRect, fHasClip ? fClip : nullptr, fAA, fColor, fMode); | |
| } | |
| DrawEdgeAAImageSetCommand::DrawEdgeAAImageSetCommand(const SkCanvas::ImageSetEntry set[], | |
| int count, | |
| const SkPoint dstClips[], | |
| const SkMatrix preViewMatrices[], | |
| const SkSamplingOptions& sampling, | |
| const SkPaint* paint, | |
| SkCanvas::SrcRectConstraint constraint) | |
| : INHERITED(kDrawEdgeAAImageSet_OpType) | |
| , fSet(count) | |
| , fCount(count) | |
| , fSampling(sampling) | |
| , fConstraint(constraint) { | |
| assign_if_not_null(fPaint, paint); | |
| int totalDstClipCount, totalMatrixCount; | |
| SkCanvasPriv::GetDstClipAndMatrixCounts(set, count, &totalDstClipCount, &totalMatrixCount); | |
| std::copy_n(set, count, fSet.get()); | |
| fDstClips.reset(totalDstClipCount); | |
| std::copy_n(dstClips, totalDstClipCount, fDstClips.get()); | |
| fPreViewMatrices.reset(totalMatrixCount); | |
| std::copy_n(preViewMatrices, totalMatrixCount, fPreViewMatrices.get()); | |
| } | |
| void DrawEdgeAAImageSetCommand::execute(SkCanvas* canvas) const { | |
| canvas->experimental_DrawEdgeAAImageSet(fSet.get(), | |
| fCount, | |
| fDstClips.get(), | |
| fPreViewMatrices.get(), | |
| fSampling, | |
| SkOptAddressOrNull(fPaint), | |
| fConstraint); | |
| } | |
| /////////////////////////////////////////////////////////////////////////////////////////////////// | |
| DrawDrawableCommand::DrawDrawableCommand(SkDrawable* drawable, const SkMatrix* matrix) | |
| : INHERITED(kDrawDrawable_OpType) | |
| , fDrawable(SkRef(drawable)) { | |
| assign_if_not_null(fMatrix, matrix); | |
| } | |
| void DrawDrawableCommand::execute(SkCanvas* canvas) const { | |
| canvas->drawDrawable(fDrawable.get(), SkOptAddressOrNull(fMatrix)); | |
| } | |
| /////////////////////////////////////////////////////////////////////////////////////////////////// | |
| DrawVerticesCommand::DrawVerticesCommand(sk_sp<SkVertices> vertices, | |
| SkBlendMode bmode, | |
| const SkPaint& paint) | |
| : INHERITED(kDrawVertices_OpType) | |
| , fVertices(std::move(vertices)) | |
| , fBlendMode(bmode) | |
| , fPaint(paint) {} | |
| void DrawVerticesCommand::execute(SkCanvas* canvas) const { | |
| canvas->drawVertices(fVertices, fBlendMode, fPaint); | |
| } | |
| /////////////////////////////////////////////////////////////////////////////////////////////////// | |
| DrawAtlasCommand::DrawAtlasCommand(const SkImage* image, | |
| const SkRSXform xform[], | |
| const SkRect tex[], | |
| const SkColor colors[], | |
| int count, | |
| SkBlendMode bmode, | |
| const SkSamplingOptions& sampling, | |
| const SkRect* cull, | |
| const SkPaint* paint) | |
| : INHERITED(kDrawAtlas_OpType) | |
| , fImage(SkRef(image)) | |
| , fXform(xform, count) | |
| , fTex(tex, count) | |
| , fColors(colors, colors ? count : 0) | |
| , fBlendMode(bmode) | |
| , fSampling(sampling) { | |
| assign_if_not_null(fCull, cull); | |
| assign_if_not_null(fPaint, paint); | |
| } | |
| void DrawAtlasCommand::execute(SkCanvas* canvas) const { | |
| canvas->drawAtlas(fImage.get(), | |
| fXform, fTex, fColors, | |
| fBlendMode, | |
| fSampling, | |
| SkOptAddressOrNull(fCull), | |
| SkOptAddressOrNull(fPaint)); | |
| } | |
| /////////////////////////////////////////////////////////////////////////////////////////////////// | |
| RestoreCommand::RestoreCommand() : INHERITED(kRestore_OpType) {} | |
| void RestoreCommand::execute(SkCanvas* canvas) const { canvas->restore(); } | |
| SaveCommand::SaveCommand() : INHERITED(kSave_OpType) {} | |
| void SaveCommand::execute(SkCanvas* canvas) const { canvas->save(); } | |
| SaveLayerCommand::SaveLayerCommand(const SkCanvas::SaveLayerRec& rec) | |
| : INHERITED(kSaveLayer_OpType) | |
| , fBackdrop(SkSafeRef(rec.fBackdrop)) | |
| , fSaveLayerFlags(rec.fSaveLayerFlags) | |
| , fBackdropScale(SkCanvasPriv::GetBackdropScaleFactor(rec)) | |
| , fBackdropTileMode(rec.fBackdropTileMode) { | |
| assign_if_not_null(fBounds, rec.fBounds); | |
| assign_if_not_null(fPaint, rec.fPaint); | |
| } | |
| void SaveLayerCommand::execute(SkCanvas* canvas) const { | |
| // In the common case fBackdropScale == 1.f and then this is no different than a regular Rec | |
| canvas->saveLayer(SkCanvasPriv::ScaledBackdropLayer(SkOptAddressOrNull(fBounds), | |
| SkOptAddressOrNull(fPaint), | |
| fBackdrop.get(), | |
| fBackdropScale, | |
| fBackdropTileMode, | |
| fSaveLayerFlags)); | |
| } | |
| void SaveLayerCommand::toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const { | |
| INHERITED::toJSON(writer, urlDataManager); | |
| if (fBounds.has_value()) { | |
| writer.appendName(DEBUGCANVAS_ATTRIBUTE_BOUNDS); | |
| MakeJsonRect(writer, *fBounds); | |
| } | |
| if (fPaint.has_value()) { | |
| writer.appendName(DEBUGCANVAS_ATTRIBUTE_PAINT); | |
| MakeJsonPaint(writer, *fPaint, urlDataManager); | |
| } | |
| if (fBackdrop != nullptr) { | |
| writer.beginObject(DEBUGCANVAS_ATTRIBUTE_BACKDROP); | |
| flatten(fBackdrop.get(), writer, urlDataManager); | |
| writer.endObject(); // backdrop | |
| } | |
| if (fSaveLayerFlags != 0) { | |
| SkDebugf("unsupported: saveLayer flags\n"); | |
| SkASSERT(false); | |
| } | |
| } | |
| SetMatrixCommand::SetMatrixCommand(const SkMatrix& matrix) : INHERITED(kSetMatrix_OpType) { | |
| fMatrix = matrix; | |
| } | |
| void SetMatrixCommand::execute(SkCanvas* canvas) const { canvas->setMatrix(fMatrix); } | |
| void SetMatrixCommand::toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const { | |
| INHERITED::toJSON(writer, urlDataManager); | |
| writer.appendName(DEBUGCANVAS_ATTRIBUTE_MATRIX); | |
| MakeJsonMatrix(writer, fMatrix); | |
| writeMatrixType(writer, fMatrix); | |
| } | |
| SetM44Command::SetM44Command(const SkM44& matrix) : INHERITED(kSetM44_OpType) { | |
| fMatrix = matrix; | |
| } | |
| void SetM44Command::execute(SkCanvas* canvas) const { canvas->setMatrix(fMatrix); } | |
| void SetM44Command::toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const { | |
| INHERITED::toJSON(writer, urlDataManager); | |
| writer.appendName(DEBUGCANVAS_ATTRIBUTE_MATRIX); | |
| MakeJsonMatrix44(writer, fMatrix); | |
| } |