1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright 2008 The Android Open Source Project 3cb93a386Sopenharmony_ci * 4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be 5cb93a386Sopenharmony_ci * found in the LICENSE file. 6cb93a386Sopenharmony_ci */ 7cb93a386Sopenharmony_ci 8cb93a386Sopenharmony_ci#include "include/core/SkCanvas.h" 9cb93a386Sopenharmony_ci 10cb93a386Sopenharmony_ci#include "include/core/SkBlender.h" 11cb93a386Sopenharmony_ci#include "include/core/SkColorFilter.h" 12cb93a386Sopenharmony_ci#include "include/core/SkImage.h" 13cb93a386Sopenharmony_ci#include "include/core/SkImageFilter.h" 14cb93a386Sopenharmony_ci#include "include/core/SkLog.h" 15cb93a386Sopenharmony_ci#include "include/core/SkPathEffect.h" 16cb93a386Sopenharmony_ci#include "include/core/SkPicture.h" 17cb93a386Sopenharmony_ci#include "include/core/SkRRect.h" 18cb93a386Sopenharmony_ci#include "include/core/SkRasterHandleAllocator.h" 19cb93a386Sopenharmony_ci#include "include/core/SkString.h" 20cb93a386Sopenharmony_ci#include "include/core/SkTextBlob.h" 21cb93a386Sopenharmony_ci#include "include/core/SkVertices.h" 22cb93a386Sopenharmony_ci#include "include/effects/SkRuntimeEffect.h" 23cb93a386Sopenharmony_ci#include "include/private/SkTOptional.h" 24cb93a386Sopenharmony_ci#include "include/private/SkTo.h" 25cb93a386Sopenharmony_ci#include "include/utils/SkNoDrawCanvas.h" 26cb93a386Sopenharmony_ci#include "src/core/SkArenaAlloc.h" 27cb93a386Sopenharmony_ci#include "src/core/SkBitmapDevice.h" 28cb93a386Sopenharmony_ci#include "src/core/SkCanvasPriv.h" 29cb93a386Sopenharmony_ci#include "src/core/SkClipStack.h" 30cb93a386Sopenharmony_ci#include "src/core/SkColorFilterBase.h" 31cb93a386Sopenharmony_ci#include "src/core/SkDraw.h" 32cb93a386Sopenharmony_ci#include "src/core/SkGlyphRun.h" 33cb93a386Sopenharmony_ci#include "src/core/SkImageFilterCache.h" 34cb93a386Sopenharmony_ci#include "src/core/SkImageFilter_Base.h" 35cb93a386Sopenharmony_ci#include "src/core/SkLatticeIter.h" 36cb93a386Sopenharmony_ci#include "src/core/SkMSAN.h" 37cb93a386Sopenharmony_ci#include "src/core/SkMarkerStack.h" 38cb93a386Sopenharmony_ci#include "src/core/SkMatrixPriv.h" 39cb93a386Sopenharmony_ci#include "src/core/SkMatrixUtils.h" 40cb93a386Sopenharmony_ci#include "src/core/SkPaintPriv.h" 41cb93a386Sopenharmony_ci#include "src/core/SkRasterClip.h" 42cb93a386Sopenharmony_ci#include "src/core/SkSpecialImage.h" 43cb93a386Sopenharmony_ci#include "src/core/SkStrikeCache.h" 44cb93a386Sopenharmony_ci#include "src/core/SkTLazy.h" 45cb93a386Sopenharmony_ci#include "src/core/SkTextFormatParams.h" 46cb93a386Sopenharmony_ci#include "src/core/SkTraceEvent.h" 47cb93a386Sopenharmony_ci#include "src/core/SkVerticesPriv.h" 48cb93a386Sopenharmony_ci#include "src/image/SkImage_Base.h" 49cb93a386Sopenharmony_ci#include "src/image/SkSurface_Base.h" 50cb93a386Sopenharmony_ci#include "src/utils/SkPatchUtils.h" 51cb93a386Sopenharmony_ci 52cb93a386Sopenharmony_ci#include <memory> 53cb93a386Sopenharmony_ci#include <new> 54cb93a386Sopenharmony_ci 55cb93a386Sopenharmony_ci#ifdef SK_ENABLE_PATH_COMPLEXITY_DFX 56cb93a386Sopenharmony_ci#include "src/core/SkPathComplexityDfx.h" 57cb93a386Sopenharmony_ci#endif 58cb93a386Sopenharmony_ci 59cb93a386Sopenharmony_ci#if SK_SUPPORT_GPU 60cb93a386Sopenharmony_ci#include "include/gpu/GrDirectContext.h" 61cb93a386Sopenharmony_ci#include "src/gpu/BaseDevice.h" 62cb93a386Sopenharmony_ci#include "src/gpu/SkGr.h" 63cb93a386Sopenharmony_ci#if defined(SK_BUILD_FOR_ANDROID_FRAMEWORK) 64cb93a386Sopenharmony_ci# include "src/gpu/GrRenderTarget.h" 65cb93a386Sopenharmony_ci# include "src/gpu/GrRenderTargetProxy.h" 66cb93a386Sopenharmony_ci#endif 67cb93a386Sopenharmony_ci#endif 68cb93a386Sopenharmony_ci 69cb93a386Sopenharmony_ci#define RETURN_ON_NULL(ptr) do { if (nullptr == (ptr)) return; } while (0) 70cb93a386Sopenharmony_ci#define RETURN_ON_FALSE(pred) do { if (!(pred)) return; } while (0) 71cb93a386Sopenharmony_ci 72cb93a386Sopenharmony_ci// This is a test: static_assert with no message is a c++17 feature, 73cb93a386Sopenharmony_ci// and std::max() is constexpr only since the c++14 stdlib. 74cb93a386Sopenharmony_cistatic_assert(std::max(3,4) == 4); 75cb93a386Sopenharmony_ci 76cb93a386Sopenharmony_ci/////////////////////////////////////////////////////////////////////////////////////////////////// 77cb93a386Sopenharmony_ci 78cb93a386Sopenharmony_ci/* 79cb93a386Sopenharmony_ci * Return true if the drawing this rect would hit every pixels in the canvas. 80cb93a386Sopenharmony_ci * 81cb93a386Sopenharmony_ci * Returns false if 82cb93a386Sopenharmony_ci * - rect does not contain the canvas' bounds 83cb93a386Sopenharmony_ci * - paint is not fill 84cb93a386Sopenharmony_ci * - paint would blur or otherwise change the coverage of the rect 85cb93a386Sopenharmony_ci */ 86cb93a386Sopenharmony_cibool SkCanvas::wouldOverwriteEntireSurface(const SkRect* rect, const SkPaint* paint, 87cb93a386Sopenharmony_ci ShaderOverrideOpacity overrideOpacity) const { 88cb93a386Sopenharmony_ci static_assert((int)SkPaintPriv::kNone_ShaderOverrideOpacity == 89cb93a386Sopenharmony_ci (int)kNone_ShaderOverrideOpacity, 90cb93a386Sopenharmony_ci "need_matching_enums0"); 91cb93a386Sopenharmony_ci static_assert((int)SkPaintPriv::kOpaque_ShaderOverrideOpacity == 92cb93a386Sopenharmony_ci (int)kOpaque_ShaderOverrideOpacity, 93cb93a386Sopenharmony_ci "need_matching_enums1"); 94cb93a386Sopenharmony_ci static_assert((int)SkPaintPriv::kNotOpaque_ShaderOverrideOpacity == 95cb93a386Sopenharmony_ci (int)kNotOpaque_ShaderOverrideOpacity, 96cb93a386Sopenharmony_ci "need_matching_enums2"); 97cb93a386Sopenharmony_ci 98cb93a386Sopenharmony_ci const SkISize size = this->getBaseLayerSize(); 99cb93a386Sopenharmony_ci const SkRect bounds = SkRect::MakeIWH(size.width(), size.height()); 100cb93a386Sopenharmony_ci 101cb93a386Sopenharmony_ci // if we're clipped at all, we can't overwrite the entire surface 102cb93a386Sopenharmony_ci { 103cb93a386Sopenharmony_ci const SkBaseDevice* base = this->baseDevice(); 104cb93a386Sopenharmony_ci const SkBaseDevice* top = this->topDevice(); 105cb93a386Sopenharmony_ci if (base != top) { 106cb93a386Sopenharmony_ci return false; // we're in a saveLayer, so conservatively don't assume we'll overwrite 107cb93a386Sopenharmony_ci } 108cb93a386Sopenharmony_ci if (!base->clipIsWideOpen()) { 109cb93a386Sopenharmony_ci return false; 110cb93a386Sopenharmony_ci } 111cb93a386Sopenharmony_ci } 112cb93a386Sopenharmony_ci 113cb93a386Sopenharmony_ci if (rect) { 114cb93a386Sopenharmony_ci if (!this->getTotalMatrix().isScaleTranslate()) { 115cb93a386Sopenharmony_ci return false; // conservative 116cb93a386Sopenharmony_ci } 117cb93a386Sopenharmony_ci 118cb93a386Sopenharmony_ci SkRect devRect; 119cb93a386Sopenharmony_ci this->getTotalMatrix().mapRectScaleTranslate(&devRect, *rect); 120cb93a386Sopenharmony_ci if (!devRect.contains(bounds)) { 121cb93a386Sopenharmony_ci return false; 122cb93a386Sopenharmony_ci } 123cb93a386Sopenharmony_ci } 124cb93a386Sopenharmony_ci 125cb93a386Sopenharmony_ci if (paint) { 126cb93a386Sopenharmony_ci SkPaint::Style paintStyle = paint->getStyle(); 127cb93a386Sopenharmony_ci if (!(paintStyle == SkPaint::kFill_Style || 128cb93a386Sopenharmony_ci paintStyle == SkPaint::kStrokeAndFill_Style)) { 129cb93a386Sopenharmony_ci return false; 130cb93a386Sopenharmony_ci } 131cb93a386Sopenharmony_ci if (paint->getMaskFilter() || paint->getPathEffect() || paint->getImageFilter()) { 132cb93a386Sopenharmony_ci return false; // conservative 133cb93a386Sopenharmony_ci } 134cb93a386Sopenharmony_ci } 135cb93a386Sopenharmony_ci return SkPaintPriv::Overwrites(paint, (SkPaintPriv::ShaderOverrideOpacity)overrideOpacity); 136cb93a386Sopenharmony_ci} 137cb93a386Sopenharmony_ci 138cb93a386Sopenharmony_ci/////////////////////////////////////////////////////////////////////////////////////////////////// 139cb93a386Sopenharmony_ci 140cb93a386Sopenharmony_ci// experimental for faster tiled drawing... 141cb93a386Sopenharmony_ci//#define SK_TRACE_SAVERESTORE 142cb93a386Sopenharmony_ci 143cb93a386Sopenharmony_ci#ifdef SK_TRACE_SAVERESTORE 144cb93a386Sopenharmony_ci static int gLayerCounter; 145cb93a386Sopenharmony_ci static void inc_layer() { ++gLayerCounter; printf("----- inc layer %d\n", gLayerCounter); } 146cb93a386Sopenharmony_ci static void dec_layer() { --gLayerCounter; printf("----- dec layer %d\n", gLayerCounter); } 147cb93a386Sopenharmony_ci 148cb93a386Sopenharmony_ci static int gRecCounter; 149cb93a386Sopenharmony_ci static void inc_rec() { ++gRecCounter; printf("----- inc rec %d\n", gRecCounter); } 150cb93a386Sopenharmony_ci static void dec_rec() { --gRecCounter; printf("----- dec rec %d\n", gRecCounter); } 151cb93a386Sopenharmony_ci 152cb93a386Sopenharmony_ci static int gCanvasCounter; 153cb93a386Sopenharmony_ci static void inc_canvas() { ++gCanvasCounter; printf("----- inc canvas %d\n", gCanvasCounter); } 154cb93a386Sopenharmony_ci static void dec_canvas() { --gCanvasCounter; printf("----- dec canvas %d\n", gCanvasCounter); } 155cb93a386Sopenharmony_ci#else 156cb93a386Sopenharmony_ci #define inc_layer() 157cb93a386Sopenharmony_ci #define dec_layer() 158cb93a386Sopenharmony_ci #define inc_rec() 159cb93a386Sopenharmony_ci #define dec_rec() 160cb93a386Sopenharmony_ci #define inc_canvas() 161cb93a386Sopenharmony_ci #define dec_canvas() 162cb93a386Sopenharmony_ci#endif 163cb93a386Sopenharmony_ci 164cb93a386Sopenharmony_cibool SkCanvas::predrawNotify(bool willOverwritesEntireSurface) { 165cb93a386Sopenharmony_ci if (fSurfaceBase) { 166cb93a386Sopenharmony_ci if (!fSurfaceBase->aboutToDraw(willOverwritesEntireSurface 167cb93a386Sopenharmony_ci ? SkSurface::kDiscard_ContentChangeMode 168cb93a386Sopenharmony_ci : SkSurface::kRetain_ContentChangeMode)) { 169cb93a386Sopenharmony_ci return false; 170cb93a386Sopenharmony_ci } 171cb93a386Sopenharmony_ci } 172cb93a386Sopenharmony_ci return true; 173cb93a386Sopenharmony_ci} 174cb93a386Sopenharmony_ci 175cb93a386Sopenharmony_cibool SkCanvas::predrawNotify(const SkRect* rect, const SkPaint* paint, 176cb93a386Sopenharmony_ci ShaderOverrideOpacity overrideOpacity) { 177cb93a386Sopenharmony_ci if (fSurfaceBase) { 178cb93a386Sopenharmony_ci SkSurface::ContentChangeMode mode = SkSurface::kRetain_ContentChangeMode; 179cb93a386Sopenharmony_ci // Since willOverwriteAllPixels() may not be complete free to call, we only do so if 180cb93a386Sopenharmony_ci // there is an outstanding snapshot, since w/o that, there will be no copy-on-write 181cb93a386Sopenharmony_ci // and therefore we don't care which mode we're in. 182cb93a386Sopenharmony_ci // 183cb93a386Sopenharmony_ci if (fSurfaceBase->outstandingImageSnapshot()) { 184cb93a386Sopenharmony_ci if (this->wouldOverwriteEntireSurface(rect, paint, overrideOpacity)) { 185cb93a386Sopenharmony_ci mode = SkSurface::kDiscard_ContentChangeMode; 186cb93a386Sopenharmony_ci } 187cb93a386Sopenharmony_ci } 188cb93a386Sopenharmony_ci if (!fSurfaceBase->aboutToDraw(mode)) { 189cb93a386Sopenharmony_ci return false; 190cb93a386Sopenharmony_ci } 191cb93a386Sopenharmony_ci } 192cb93a386Sopenharmony_ci return true; 193cb93a386Sopenharmony_ci} 194cb93a386Sopenharmony_ci 195cb93a386Sopenharmony_ci/////////////////////////////////////////////////////////////////////////////// 196cb93a386Sopenharmony_ci 197cb93a386Sopenharmony_ciSkCanvas::Layer::Layer(sk_sp<SkBaseDevice> device, 198cb93a386Sopenharmony_ci sk_sp<SkImageFilter> imageFilter, 199cb93a386Sopenharmony_ci const SkPaint& paint) 200cb93a386Sopenharmony_ci : fDevice(std::move(device)) 201cb93a386Sopenharmony_ci , fImageFilter(std::move(imageFilter)) 202cb93a386Sopenharmony_ci , fPaint(paint) 203cb93a386Sopenharmony_ci , fDiscard(false) { 204cb93a386Sopenharmony_ci SkASSERT(fDevice); 205cb93a386Sopenharmony_ci // Any image filter should have been pulled out and stored in 'imageFilter' so that 'paint' 206cb93a386Sopenharmony_ci // can be used as-is to draw the result of the filter to the dst device. 207cb93a386Sopenharmony_ci SkASSERT(!fPaint.getImageFilter()); 208cb93a386Sopenharmony_ci} 209cb93a386Sopenharmony_ci 210cb93a386Sopenharmony_ciSkCanvas::MCRec::MCRec(SkBaseDevice* device) : fDevice(device) { 211cb93a386Sopenharmony_ci SkASSERT(fDevice); 212cb93a386Sopenharmony_ci inc_rec(); 213cb93a386Sopenharmony_ci} 214cb93a386Sopenharmony_ci 215cb93a386Sopenharmony_ciSkCanvas::MCRec::MCRec(const MCRec* prev) : fDevice(prev->fDevice), fMatrix(prev->fMatrix) { 216cb93a386Sopenharmony_ci SkASSERT(fDevice); 217cb93a386Sopenharmony_ci inc_rec(); 218cb93a386Sopenharmony_ci} 219cb93a386Sopenharmony_ci 220cb93a386Sopenharmony_ciSkCanvas::MCRec::~MCRec() { dec_rec(); } 221cb93a386Sopenharmony_ci 222cb93a386Sopenharmony_civoid SkCanvas::MCRec::newLayer(sk_sp<SkBaseDevice> layerDevice, 223cb93a386Sopenharmony_ci sk_sp<SkImageFilter> filter, 224cb93a386Sopenharmony_ci const SkPaint& restorePaint) { 225cb93a386Sopenharmony_ci SkASSERT(!fBackImage); 226cb93a386Sopenharmony_ci fLayer = std::make_unique<Layer>(std::move(layerDevice), std::move(filter), restorePaint); 227cb93a386Sopenharmony_ci fDevice = fLayer->fDevice.get(); 228cb93a386Sopenharmony_ci} 229cb93a386Sopenharmony_ci 230cb93a386Sopenharmony_civoid SkCanvas::MCRec::reset(SkBaseDevice* device) { 231cb93a386Sopenharmony_ci SkASSERT(!fLayer); 232cb93a386Sopenharmony_ci SkASSERT(device); 233cb93a386Sopenharmony_ci SkASSERT(fDeferredSaveCount == 0); 234cb93a386Sopenharmony_ci fDevice = device; 235cb93a386Sopenharmony_ci fMatrix.setIdentity(); 236cb93a386Sopenharmony_ci} 237cb93a386Sopenharmony_ci 238cb93a386Sopenharmony_ciclass SkCanvas::AutoUpdateQRBounds { 239cb93a386Sopenharmony_cipublic: 240cb93a386Sopenharmony_ci explicit AutoUpdateQRBounds(SkCanvas* canvas) : fCanvas(canvas) { 241cb93a386Sopenharmony_ci // pre-condition, fQuickRejectBounds and other state should be valid before anything 242cb93a386Sopenharmony_ci // modifies the device's clip. 243cb93a386Sopenharmony_ci fCanvas->validateClip(); 244cb93a386Sopenharmony_ci } 245cb93a386Sopenharmony_ci ~AutoUpdateQRBounds() { 246cb93a386Sopenharmony_ci fCanvas->fQuickRejectBounds = fCanvas->computeDeviceClipBounds(); 247cb93a386Sopenharmony_ci // post-condition, we should remain valid after re-computing the bounds 248cb93a386Sopenharmony_ci fCanvas->validateClip(); 249cb93a386Sopenharmony_ci } 250cb93a386Sopenharmony_ci 251cb93a386Sopenharmony_ciprivate: 252cb93a386Sopenharmony_ci SkCanvas* fCanvas; 253cb93a386Sopenharmony_ci 254cb93a386Sopenharmony_ci AutoUpdateQRBounds(AutoUpdateQRBounds&&) = delete; 255cb93a386Sopenharmony_ci AutoUpdateQRBounds(const AutoUpdateQRBounds&) = delete; 256cb93a386Sopenharmony_ci AutoUpdateQRBounds& operator=(AutoUpdateQRBounds&&) = delete; 257cb93a386Sopenharmony_ci AutoUpdateQRBounds& operator=(const AutoUpdateQRBounds&) = delete; 258cb93a386Sopenharmony_ci}; 259cb93a386Sopenharmony_ci 260cb93a386Sopenharmony_ci///////////////////////////////////////////////////////////////////////////// 261cb93a386Sopenharmony_ci// Attempts to convert an image filter to its equivalent color filter, which if possible, modifies 262cb93a386Sopenharmony_ci// the paint to compose the image filter's color filter into the paint's color filter slot. 263cb93a386Sopenharmony_ci// Returns true if the paint has been modified. 264cb93a386Sopenharmony_ci// Requires the paint to have an image filter and the copy-on-write be initialized. 265cb93a386Sopenharmony_cistatic bool image_to_color_filter(SkPaint* paint) { 266cb93a386Sopenharmony_ci SkASSERT(SkToBool(paint) && paint->getImageFilter()); 267cb93a386Sopenharmony_ci 268cb93a386Sopenharmony_ci SkColorFilter* imgCFPtr; 269cb93a386Sopenharmony_ci if (!paint->getImageFilter()->asAColorFilter(&imgCFPtr)) { 270cb93a386Sopenharmony_ci return false; 271cb93a386Sopenharmony_ci } 272cb93a386Sopenharmony_ci sk_sp<SkColorFilter> imgCF(imgCFPtr); 273cb93a386Sopenharmony_ci 274cb93a386Sopenharmony_ci SkColorFilter* paintCF = paint->getColorFilter(); 275cb93a386Sopenharmony_ci if (paintCF) { 276cb93a386Sopenharmony_ci // The paint has both a colorfilter(paintCF) and an imagefilter-that-is-a-colorfilter(imgCF) 277cb93a386Sopenharmony_ci // and we need to combine them into a single colorfilter. 278cb93a386Sopenharmony_ci imgCF = imgCF->makeComposed(sk_ref_sp(paintCF)); 279cb93a386Sopenharmony_ci } 280cb93a386Sopenharmony_ci 281cb93a386Sopenharmony_ci paint->setColorFilter(std::move(imgCF)); 282cb93a386Sopenharmony_ci paint->setImageFilter(nullptr); 283cb93a386Sopenharmony_ci return true; 284cb93a386Sopenharmony_ci} 285cb93a386Sopenharmony_ci 286cb93a386Sopenharmony_ci/** 287cb93a386Sopenharmony_ci * We implement ImageFilters for a given draw by creating a layer, then applying the 288cb93a386Sopenharmony_ci * imagefilter to the pixels of that layer (its backing surface/image), and then 289cb93a386Sopenharmony_ci * we call restore() to xfer that layer to the main canvas. 290cb93a386Sopenharmony_ci * 291cb93a386Sopenharmony_ci * 1. SaveLayer (with a paint containing the current imagefilter and xfermode) 292cb93a386Sopenharmony_ci * 2. Generate the src pixels: 293cb93a386Sopenharmony_ci * Remove the imagefilter and the xfermode from the paint that we (AutoDrawLooper) 294cb93a386Sopenharmony_ci * return (fPaint). We then draw the primitive (using srcover) into a cleared 295cb93a386Sopenharmony_ci * buffer/surface. 296cb93a386Sopenharmony_ci * 3. Restore the layer created in #1 297cb93a386Sopenharmony_ci * The imagefilter is passed the buffer/surface from the layer (now filled with the 298cb93a386Sopenharmony_ci * src pixels of the primitive). It returns a new "filtered" buffer, which we 299cb93a386Sopenharmony_ci * draw onto the previous layer using the xfermode from the original paint. 300cb93a386Sopenharmony_ci */ 301cb93a386Sopenharmony_ciclass AutoLayerForImageFilter { 302cb93a386Sopenharmony_cipublic: 303cb93a386Sopenharmony_ci // "rawBounds" is the original bounds of the primitive about to be drawn, unmodified by the 304cb93a386Sopenharmony_ci // paint. It's used to determine the size of the offscreen layer for filters. 305cb93a386Sopenharmony_ci // If null, the clip will be used instead. 306cb93a386Sopenharmony_ci // 307cb93a386Sopenharmony_ci // Draw functions should use layer->paint() instead of the passed-in paint. 308cb93a386Sopenharmony_ci AutoLayerForImageFilter(SkCanvas* canvas, 309cb93a386Sopenharmony_ci const SkPaint& paint, 310cb93a386Sopenharmony_ci const SkRect* rawBounds = nullptr) 311cb93a386Sopenharmony_ci : fPaint(paint) 312cb93a386Sopenharmony_ci , fCanvas(canvas) 313cb93a386Sopenharmony_ci , fTempLayerForImageFilter(false) { 314cb93a386Sopenharmony_ci SkDEBUGCODE(fSaveCount = canvas->getSaveCount();) 315cb93a386Sopenharmony_ci 316cb93a386Sopenharmony_ci if (fPaint.getImageFilter() && !image_to_color_filter(&fPaint)) { 317cb93a386Sopenharmony_ci // The draw paint has an image filter that couldn't be simplified to an equivalent 318cb93a386Sopenharmony_ci // color filter, so we have to inject an automatic saveLayer(). 319cb93a386Sopenharmony_ci SkPaint restorePaint; 320cb93a386Sopenharmony_ci restorePaint.setImageFilter(fPaint.refImageFilter()); 321cb93a386Sopenharmony_ci restorePaint.setBlender(fPaint.refBlender()); 322cb93a386Sopenharmony_ci 323cb93a386Sopenharmony_ci // Remove the restorePaint fields from our "working" paint 324cb93a386Sopenharmony_ci fPaint.setImageFilter(nullptr); 325cb93a386Sopenharmony_ci fPaint.setBlendMode(SkBlendMode::kSrcOver); 326cb93a386Sopenharmony_ci 327cb93a386Sopenharmony_ci SkRect storage; 328cb93a386Sopenharmony_ci if (rawBounds && fPaint.canComputeFastBounds()) { 329cb93a386Sopenharmony_ci // Make rawBounds include all paint outsets except for those due to image filters. 330cb93a386Sopenharmony_ci // At this point, fPaint's image filter has been moved to 'restorePaint'. 331cb93a386Sopenharmony_ci SkASSERT(!fPaint.getImageFilter()); 332cb93a386Sopenharmony_ci rawBounds = &fPaint.computeFastBounds(*rawBounds, &storage); 333cb93a386Sopenharmony_ci } 334cb93a386Sopenharmony_ci 335cb93a386Sopenharmony_ci (void)canvas->internalSaveLayer(SkCanvas::SaveLayerRec(rawBounds, &restorePaint), 336cb93a386Sopenharmony_ci SkCanvas::kFullLayer_SaveLayerStrategy); 337cb93a386Sopenharmony_ci fTempLayerForImageFilter = true; 338cb93a386Sopenharmony_ci } 339cb93a386Sopenharmony_ci } 340cb93a386Sopenharmony_ci 341cb93a386Sopenharmony_ci AutoLayerForImageFilter(const AutoLayerForImageFilter&) = delete; 342cb93a386Sopenharmony_ci AutoLayerForImageFilter& operator=(const AutoLayerForImageFilter&) = delete; 343cb93a386Sopenharmony_ci AutoLayerForImageFilter(AutoLayerForImageFilter&&) = default; 344cb93a386Sopenharmony_ci AutoLayerForImageFilter& operator=(AutoLayerForImageFilter&&) = default; 345cb93a386Sopenharmony_ci 346cb93a386Sopenharmony_ci ~AutoLayerForImageFilter() { 347cb93a386Sopenharmony_ci if (fTempLayerForImageFilter) { 348cb93a386Sopenharmony_ci fCanvas->internalRestore(); 349cb93a386Sopenharmony_ci } 350cb93a386Sopenharmony_ci SkASSERT(fCanvas->getSaveCount() == fSaveCount); 351cb93a386Sopenharmony_ci } 352cb93a386Sopenharmony_ci 353cb93a386Sopenharmony_ci const SkPaint& paint() const { return fPaint; } 354cb93a386Sopenharmony_ci 355cb93a386Sopenharmony_ciprivate: 356cb93a386Sopenharmony_ci SkPaint fPaint; 357cb93a386Sopenharmony_ci SkCanvas* fCanvas; 358cb93a386Sopenharmony_ci bool fTempLayerForImageFilter; 359cb93a386Sopenharmony_ci 360cb93a386Sopenharmony_ci SkDEBUGCODE(int fSaveCount;) 361cb93a386Sopenharmony_ci}; 362cb93a386Sopenharmony_ci 363cb93a386Sopenharmony_ciskstd::optional<AutoLayerForImageFilter> SkCanvas::aboutToDraw( 364cb93a386Sopenharmony_ci SkCanvas* canvas, 365cb93a386Sopenharmony_ci const SkPaint& paint, 366cb93a386Sopenharmony_ci const SkRect* rawBounds, 367cb93a386Sopenharmony_ci CheckForOverwrite checkOverwrite, 368cb93a386Sopenharmony_ci ShaderOverrideOpacity overrideOpacity) 369cb93a386Sopenharmony_ci{ 370cb93a386Sopenharmony_ci if (checkOverwrite == CheckForOverwrite::kYes) { 371cb93a386Sopenharmony_ci if (!this->predrawNotify(rawBounds, &paint, overrideOpacity)) { 372cb93a386Sopenharmony_ci return skstd::nullopt; 373cb93a386Sopenharmony_ci } 374cb93a386Sopenharmony_ci } else { 375cb93a386Sopenharmony_ci if (!this->predrawNotify()) { 376cb93a386Sopenharmony_ci return skstd::nullopt; 377cb93a386Sopenharmony_ci } 378cb93a386Sopenharmony_ci } 379cb93a386Sopenharmony_ci return skstd::optional<AutoLayerForImageFilter>(canvas, paint, rawBounds); 380cb93a386Sopenharmony_ci} 381cb93a386Sopenharmony_ci 382cb93a386Sopenharmony_ci//////////////////////////////////////////////////////////////////////////// 383cb93a386Sopenharmony_ci 384cb93a386Sopenharmony_civoid SkCanvas::resetForNextPicture(const SkIRect& bounds) { 385cb93a386Sopenharmony_ci this->restoreToCount(1); 386cb93a386Sopenharmony_ci 387cb93a386Sopenharmony_ci // We're peering through a lot of structs here. Only at this scope do we 388cb93a386Sopenharmony_ci // know that the device is a SkNoPixelsDevice. 389cb93a386Sopenharmony_ci SkASSERT(fBaseDevice->isNoPixelsDevice()); 390cb93a386Sopenharmony_ci static_cast<SkNoPixelsDevice*>(fBaseDevice.get())->resetForNextPicture(bounds); 391cb93a386Sopenharmony_ci fMCRec->reset(fBaseDevice.get()); 392cb93a386Sopenharmony_ci fQuickRejectBounds = this->computeDeviceClipBounds(); 393cb93a386Sopenharmony_ci} 394cb93a386Sopenharmony_ci 395cb93a386Sopenharmony_civoid SkCanvas::init(sk_sp<SkBaseDevice> device) { 396cb93a386Sopenharmony_ci // SkCanvas.h declares internal storage for the hidden struct MCRec, and this 397cb93a386Sopenharmony_ci // assert ensure it's sufficient. <= is used because the struct has pointer fields, so the 398cb93a386Sopenharmony_ci // declared size is an upper bound across architectures. When the size is smaller, more stack 399cb93a386Sopenharmony_ci static_assert(sizeof(MCRec) <= kMCRecSize); 400cb93a386Sopenharmony_ci 401cb93a386Sopenharmony_ci if (!device) { 402cb93a386Sopenharmony_ci device = sk_make_sp<SkNoPixelsDevice>(SkIRect::MakeEmpty(), fProps); 403cb93a386Sopenharmony_ci } 404cb93a386Sopenharmony_ci 405cb93a386Sopenharmony_ci // From this point on, SkCanvas will always have a device 406cb93a386Sopenharmony_ci SkASSERT(device); 407cb93a386Sopenharmony_ci 408cb93a386Sopenharmony_ci fSaveCount = 1; 409cb93a386Sopenharmony_ci fMCRec = new (fMCStack.push_back()) MCRec(device.get()); 410cb93a386Sopenharmony_ci fMarkerStack = sk_make_sp<SkMarkerStack>(); 411cb93a386Sopenharmony_ci 412cb93a386Sopenharmony_ci // The root device and the canvas should always have the same pixel geometry 413cb93a386Sopenharmony_ci SkASSERT(fProps.pixelGeometry() == device->surfaceProps().pixelGeometry()); 414cb93a386Sopenharmony_ci device->setMarkerStack(fMarkerStack.get()); 415cb93a386Sopenharmony_ci 416cb93a386Sopenharmony_ci fSurfaceBase = nullptr; 417cb93a386Sopenharmony_ci fBaseDevice = std::move(device); 418cb93a386Sopenharmony_ci fScratchGlyphRunBuilder = std::make_unique<SkGlyphRunBuilder>(); 419cb93a386Sopenharmony_ci fQuickRejectBounds = this->computeDeviceClipBounds(); 420cb93a386Sopenharmony_ci} 421cb93a386Sopenharmony_ci 422cb93a386Sopenharmony_ciSkCanvas::SkCanvas() : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage)) { 423cb93a386Sopenharmony_ci inc_canvas(); 424cb93a386Sopenharmony_ci this->init(nullptr); 425cb93a386Sopenharmony_ci} 426cb93a386Sopenharmony_ci 427cb93a386Sopenharmony_ciSkCanvas::SkCanvas(int width, int height, const SkSurfaceProps* props) 428cb93a386Sopenharmony_ci : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage)) 429cb93a386Sopenharmony_ci , fProps(SkSurfacePropsCopyOrDefault(props)) { 430cb93a386Sopenharmony_ci inc_canvas(); 431cb93a386Sopenharmony_ci this->init(sk_make_sp<SkNoPixelsDevice>( 432cb93a386Sopenharmony_ci SkIRect::MakeWH(std::max(width, 0), std::max(height, 0)), fProps)); 433cb93a386Sopenharmony_ci} 434cb93a386Sopenharmony_ci 435cb93a386Sopenharmony_ciSkCanvas::SkCanvas(const SkIRect& bounds) 436cb93a386Sopenharmony_ci : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage)) { 437cb93a386Sopenharmony_ci inc_canvas(); 438cb93a386Sopenharmony_ci 439cb93a386Sopenharmony_ci SkIRect r = bounds.isEmpty() ? SkIRect::MakeEmpty() : bounds; 440cb93a386Sopenharmony_ci this->init(sk_make_sp<SkNoPixelsDevice>(r, fProps)); 441cb93a386Sopenharmony_ci} 442cb93a386Sopenharmony_ci 443cb93a386Sopenharmony_ciSkCanvas::SkCanvas(sk_sp<SkBaseDevice> device) 444cb93a386Sopenharmony_ci : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage)) 445cb93a386Sopenharmony_ci , fProps(device->surfaceProps()) { 446cb93a386Sopenharmony_ci inc_canvas(); 447cb93a386Sopenharmony_ci 448cb93a386Sopenharmony_ci this->init(device); 449cb93a386Sopenharmony_ci} 450cb93a386Sopenharmony_ci 451cb93a386Sopenharmony_ciSkCanvas::SkCanvas(const SkBitmap& bitmap, const SkSurfaceProps& props) 452cb93a386Sopenharmony_ci : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage)), fProps(props) { 453cb93a386Sopenharmony_ci inc_canvas(); 454cb93a386Sopenharmony_ci 455cb93a386Sopenharmony_ci sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps, nullptr, nullptr)); 456cb93a386Sopenharmony_ci this->init(device); 457cb93a386Sopenharmony_ci} 458cb93a386Sopenharmony_ci 459cb93a386Sopenharmony_ciSkCanvas::SkCanvas(const SkBitmap& bitmap, 460cb93a386Sopenharmony_ci std::unique_ptr<SkRasterHandleAllocator> alloc, 461cb93a386Sopenharmony_ci SkRasterHandleAllocator::Handle hndl) 462cb93a386Sopenharmony_ci : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage)) 463cb93a386Sopenharmony_ci , fAllocator(std::move(alloc)) { 464cb93a386Sopenharmony_ci inc_canvas(); 465cb93a386Sopenharmony_ci 466cb93a386Sopenharmony_ci sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps, hndl, nullptr)); 467cb93a386Sopenharmony_ci this->init(device); 468cb93a386Sopenharmony_ci} 469cb93a386Sopenharmony_ci 470cb93a386Sopenharmony_ciSkCanvas::SkCanvas(const SkBitmap& bitmap) : SkCanvas(bitmap, nullptr, nullptr) {} 471cb93a386Sopenharmony_ci 472cb93a386Sopenharmony_ci#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK 473cb93a386Sopenharmony_ciSkCanvas::SkCanvas(const SkBitmap& bitmap, ColorBehavior) 474cb93a386Sopenharmony_ci : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage)) { 475cb93a386Sopenharmony_ci inc_canvas(); 476cb93a386Sopenharmony_ci 477cb93a386Sopenharmony_ci SkBitmap tmp(bitmap); 478cb93a386Sopenharmony_ci *const_cast<SkImageInfo*>(&tmp.info()) = tmp.info().makeColorSpace(nullptr); 479cb93a386Sopenharmony_ci sk_sp<SkBaseDevice> device(new SkBitmapDevice(tmp, fProps, nullptr, nullptr)); 480cb93a386Sopenharmony_ci this->init(device); 481cb93a386Sopenharmony_ci} 482cb93a386Sopenharmony_ci#endif 483cb93a386Sopenharmony_ci 484cb93a386Sopenharmony_ciSkCanvas::~SkCanvas() { 485cb93a386Sopenharmony_ci // Mark all pending layers to be discarded during restore (rather than drawn) 486cb93a386Sopenharmony_ci SkDeque::Iter iter(fMCStack, SkDeque::Iter::kFront_IterStart); 487cb93a386Sopenharmony_ci for (;;) { 488cb93a386Sopenharmony_ci MCRec* rec = (MCRec*)iter.next(); 489cb93a386Sopenharmony_ci if (!rec) { 490cb93a386Sopenharmony_ci break; 491cb93a386Sopenharmony_ci } 492cb93a386Sopenharmony_ci if (rec->fLayer) { 493cb93a386Sopenharmony_ci rec->fLayer->fDiscard = true; 494cb93a386Sopenharmony_ci } 495cb93a386Sopenharmony_ci } 496cb93a386Sopenharmony_ci 497cb93a386Sopenharmony_ci // free up the contents of our deque 498cb93a386Sopenharmony_ci this->restoreToCount(1); // restore everything but the last 499cb93a386Sopenharmony_ci this->internalRestore(); // restore the last, since we're going away 500cb93a386Sopenharmony_ci 501cb93a386Sopenharmony_ci dec_canvas(); 502cb93a386Sopenharmony_ci} 503cb93a386Sopenharmony_ci 504cb93a386Sopenharmony_ci/////////////////////////////////////////////////////////////////////////////// 505cb93a386Sopenharmony_ci 506cb93a386Sopenharmony_civoid SkCanvas::flush() { 507cb93a386Sopenharmony_ci this->onFlush(); 508cb93a386Sopenharmony_ci} 509cb93a386Sopenharmony_ci 510cb93a386Sopenharmony_civoid SkCanvas::onFlush() { 511cb93a386Sopenharmony_ci#if SK_SUPPORT_GPU 512cb93a386Sopenharmony_ci auto dContext = GrAsDirectContext(this->recordingContext()); 513cb93a386Sopenharmony_ci 514cb93a386Sopenharmony_ci if (dContext) { 515cb93a386Sopenharmony_ci dContext->flushAndSubmit(); 516cb93a386Sopenharmony_ci } 517cb93a386Sopenharmony_ci#endif 518cb93a386Sopenharmony_ci} 519cb93a386Sopenharmony_ci 520cb93a386Sopenharmony_ciSkSurface* SkCanvas::getSurface() const { 521cb93a386Sopenharmony_ci return fSurfaceBase; 522cb93a386Sopenharmony_ci} 523cb93a386Sopenharmony_ci 524cb93a386Sopenharmony_ciSkISize SkCanvas::getBaseLayerSize() const { 525cb93a386Sopenharmony_ci return this->baseDevice()->imageInfo().dimensions(); 526cb93a386Sopenharmony_ci} 527cb93a386Sopenharmony_ci 528cb93a386Sopenharmony_ciSkBaseDevice* SkCanvas::topDevice() const { 529cb93a386Sopenharmony_ci SkASSERT(fMCRec->fDevice); 530cb93a386Sopenharmony_ci return fMCRec->fDevice; 531cb93a386Sopenharmony_ci} 532cb93a386Sopenharmony_ci 533cb93a386Sopenharmony_cibool SkCanvas::readPixels(const SkPixmap& pm, int x, int y) { 534cb93a386Sopenharmony_ci return pm.addr() && this->baseDevice()->readPixels(pm, x, y); 535cb93a386Sopenharmony_ci} 536cb93a386Sopenharmony_ci 537cb93a386Sopenharmony_cibool SkCanvas::readPixels(const SkImageInfo& dstInfo, void* dstP, size_t rowBytes, int x, int y) { 538cb93a386Sopenharmony_ci return this->readPixels({ dstInfo, dstP, rowBytes}, x, y); 539cb93a386Sopenharmony_ci} 540cb93a386Sopenharmony_ci 541cb93a386Sopenharmony_cibool SkCanvas::readPixels(const SkBitmap& bm, int x, int y) { 542cb93a386Sopenharmony_ci SkPixmap pm; 543cb93a386Sopenharmony_ci return bm.peekPixels(&pm) && this->readPixels(pm, x, y); 544cb93a386Sopenharmony_ci} 545cb93a386Sopenharmony_ci 546cb93a386Sopenharmony_cibool SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y) { 547cb93a386Sopenharmony_ci SkPixmap pm; 548cb93a386Sopenharmony_ci if (bitmap.peekPixels(&pm)) { 549cb93a386Sopenharmony_ci return this->writePixels(pm.info(), pm.addr(), pm.rowBytes(), x, y); 550cb93a386Sopenharmony_ci } 551cb93a386Sopenharmony_ci return false; 552cb93a386Sopenharmony_ci} 553cb93a386Sopenharmony_ci 554cb93a386Sopenharmony_cibool SkCanvas::writePixels(const SkImageInfo& srcInfo, const void* pixels, size_t rowBytes, 555cb93a386Sopenharmony_ci int x, int y) { 556cb93a386Sopenharmony_ci SkBaseDevice* device = this->baseDevice(); 557cb93a386Sopenharmony_ci 558cb93a386Sopenharmony_ci // This check gives us an early out and prevents generation ID churn on the surface. 559cb93a386Sopenharmony_ci // This is purely optional: it is a subset of the checks performed by SkWritePixelsRec. 560cb93a386Sopenharmony_ci SkIRect srcRect = SkIRect::MakeXYWH(x, y, srcInfo.width(), srcInfo.height()); 561cb93a386Sopenharmony_ci if (!srcRect.intersect({0, 0, device->width(), device->height()})) { 562cb93a386Sopenharmony_ci return false; 563cb93a386Sopenharmony_ci } 564cb93a386Sopenharmony_ci 565cb93a386Sopenharmony_ci // Tell our owning surface to bump its generation ID. 566cb93a386Sopenharmony_ci const bool completeOverwrite = srcRect.size() == device->imageInfo().dimensions(); 567cb93a386Sopenharmony_ci if (!this->predrawNotify(completeOverwrite)) { 568cb93a386Sopenharmony_ci return false; 569cb93a386Sopenharmony_ci } 570cb93a386Sopenharmony_ci 571cb93a386Sopenharmony_ci // This can still fail, most notably in the case of a invalid color type or alpha type 572cb93a386Sopenharmony_ci // conversion. We could pull those checks into this function and avoid the unnecessary 573cb93a386Sopenharmony_ci // generation ID bump. But then we would be performing those checks twice, since they 574cb93a386Sopenharmony_ci // are also necessary at the bitmap/pixmap entry points. 575cb93a386Sopenharmony_ci return device->writePixels({srcInfo, pixels, rowBytes}, x, y); 576cb93a386Sopenharmony_ci} 577cb93a386Sopenharmony_ci 578cb93a386Sopenharmony_ci////////////////////////////////////////////////////////////////////////////// 579cb93a386Sopenharmony_ci 580cb93a386Sopenharmony_civoid SkCanvas::checkForDeferredSave() { 581cb93a386Sopenharmony_ci if (fMCRec->fDeferredSaveCount > 0) { 582cb93a386Sopenharmony_ci this->doSave(); 583cb93a386Sopenharmony_ci } 584cb93a386Sopenharmony_ci} 585cb93a386Sopenharmony_ci 586cb93a386Sopenharmony_ciint SkCanvas::getSaveCount() const { 587cb93a386Sopenharmony_ci#ifdef SK_DEBUG 588cb93a386Sopenharmony_ci int count = 0; 589cb93a386Sopenharmony_ci SkDeque::Iter iter(fMCStack, SkDeque::Iter::kFront_IterStart); 590cb93a386Sopenharmony_ci for (;;) { 591cb93a386Sopenharmony_ci const MCRec* rec = (const MCRec*)iter.next(); 592cb93a386Sopenharmony_ci if (!rec) { 593cb93a386Sopenharmony_ci break; 594cb93a386Sopenharmony_ci } 595cb93a386Sopenharmony_ci count += 1 + rec->fDeferredSaveCount; 596cb93a386Sopenharmony_ci } 597cb93a386Sopenharmony_ci SkASSERT(count == fSaveCount); 598cb93a386Sopenharmony_ci#endif 599cb93a386Sopenharmony_ci return fSaveCount; 600cb93a386Sopenharmony_ci} 601cb93a386Sopenharmony_ci 602cb93a386Sopenharmony_ciint SkCanvas::save() { 603cb93a386Sopenharmony_ci fSaveCount += 1; 604cb93a386Sopenharmony_ci fMCRec->fDeferredSaveCount += 1; 605cb93a386Sopenharmony_ci return this->getSaveCount() - 1; // return our prev value 606cb93a386Sopenharmony_ci} 607cb93a386Sopenharmony_ci 608cb93a386Sopenharmony_civoid SkCanvas::doSave() { 609cb93a386Sopenharmony_ci this->willSave(); 610cb93a386Sopenharmony_ci 611cb93a386Sopenharmony_ci SkASSERT(fMCRec->fDeferredSaveCount > 0); 612cb93a386Sopenharmony_ci fMCRec->fDeferredSaveCount -= 1; 613cb93a386Sopenharmony_ci this->internalSave(); 614cb93a386Sopenharmony_ci} 615cb93a386Sopenharmony_ci 616cb93a386Sopenharmony_civoid SkCanvas::restore() { 617cb93a386Sopenharmony_ci if (fMCRec->fDeferredSaveCount > 0) { 618cb93a386Sopenharmony_ci SkASSERT(fSaveCount > 1); 619cb93a386Sopenharmony_ci fSaveCount -= 1; 620cb93a386Sopenharmony_ci fMCRec->fDeferredSaveCount -= 1; 621cb93a386Sopenharmony_ci } else { 622cb93a386Sopenharmony_ci // check for underflow 623cb93a386Sopenharmony_ci if (fMCStack.count() > 1) { 624cb93a386Sopenharmony_ci this->willRestore(); 625cb93a386Sopenharmony_ci SkASSERT(fSaveCount > 1); 626cb93a386Sopenharmony_ci fSaveCount -= 1; 627cb93a386Sopenharmony_ci this->internalRestore(); 628cb93a386Sopenharmony_ci this->didRestore(); 629cb93a386Sopenharmony_ci } 630cb93a386Sopenharmony_ci } 631cb93a386Sopenharmony_ci} 632cb93a386Sopenharmony_ci 633cb93a386Sopenharmony_civoid SkCanvas::restoreToCount(int count) { 634cb93a386Sopenharmony_ci // safety check 635cb93a386Sopenharmony_ci if (count < 1) { 636cb93a386Sopenharmony_ci count = 1; 637cb93a386Sopenharmony_ci } 638cb93a386Sopenharmony_ci 639cb93a386Sopenharmony_ci int n = this->getSaveCount() - count; 640cb93a386Sopenharmony_ci for (int i = 0; i < n; ++i) { 641cb93a386Sopenharmony_ci this->restore(); 642cb93a386Sopenharmony_ci } 643cb93a386Sopenharmony_ci} 644cb93a386Sopenharmony_ci 645cb93a386Sopenharmony_civoid SkCanvas::internalSave() { 646cb93a386Sopenharmony_ci fMCRec = new (fMCStack.push_back()) MCRec(fMCRec); 647cb93a386Sopenharmony_ci 648cb93a386Sopenharmony_ci this->topDevice()->save(); 649cb93a386Sopenharmony_ci} 650cb93a386Sopenharmony_ci 651cb93a386Sopenharmony_ciint SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint) { 652cb93a386Sopenharmony_ci return this->saveLayer(SaveLayerRec(bounds, paint, 0)); 653cb93a386Sopenharmony_ci} 654cb93a386Sopenharmony_ci 655cb93a386Sopenharmony_ciint SkCanvas::saveLayer(const SaveLayerRec& rec) { 656cb93a386Sopenharmony_ci TRACE_EVENT0("skia", TRACE_FUNC); 657cb93a386Sopenharmony_ci if (rec.fPaint && rec.fPaint->nothingToDraw()) { 658cb93a386Sopenharmony_ci // no need for the layer (or any of the draws until the matching restore() 659cb93a386Sopenharmony_ci this->save(); 660cb93a386Sopenharmony_ci this->clipRect({0,0,0,0}); 661cb93a386Sopenharmony_ci } else { 662cb93a386Sopenharmony_ci SaveLayerStrategy strategy = this->getSaveLayerStrategy(rec); 663cb93a386Sopenharmony_ci fSaveCount += 1; 664cb93a386Sopenharmony_ci this->internalSaveLayer(rec, strategy); 665cb93a386Sopenharmony_ci } 666cb93a386Sopenharmony_ci return this->getSaveCount() - 1; 667cb93a386Sopenharmony_ci} 668cb93a386Sopenharmony_ci 669cb93a386Sopenharmony_ciint SkCanvas::only_axis_aligned_saveBehind(const SkRect* bounds) { 670cb93a386Sopenharmony_ci if (bounds && !this->getLocalClipBounds().intersects(*bounds)) { 671cb93a386Sopenharmony_ci // Assuming clips never expand, if the request bounds is outside of the current clip 672cb93a386Sopenharmony_ci // there is no need to copy/restore the area, so just devolve back to a regular save. 673cb93a386Sopenharmony_ci this->save(); 674cb93a386Sopenharmony_ci } else { 675cb93a386Sopenharmony_ci bool doTheWork = this->onDoSaveBehind(bounds); 676cb93a386Sopenharmony_ci fSaveCount += 1; 677cb93a386Sopenharmony_ci this->internalSave(); 678cb93a386Sopenharmony_ci if (doTheWork) { 679cb93a386Sopenharmony_ci this->internalSaveBehind(bounds); 680cb93a386Sopenharmony_ci } 681cb93a386Sopenharmony_ci } 682cb93a386Sopenharmony_ci return this->getSaveCount() - 1; 683cb93a386Sopenharmony_ci} 684cb93a386Sopenharmony_ci 685cb93a386Sopenharmony_ci// In our current design/features, we should never have a layer (src) in a different colorspace 686cb93a386Sopenharmony_ci// than its parent (dst), so we assert that here. This is called out from other asserts, in case 687cb93a386Sopenharmony_ci// we add some feature in the future to allow a given layer/imagefilter to operate in a specific 688cb93a386Sopenharmony_ci// colorspace. 689cb93a386Sopenharmony_cistatic void check_drawdevice_colorspaces(SkColorSpace* src, SkColorSpace* dst) { 690cb93a386Sopenharmony_ci SkASSERT(src == dst); 691cb93a386Sopenharmony_ci} 692cb93a386Sopenharmony_ci 693cb93a386Sopenharmony_ci// Helper function to compute the center reference point used for scale decomposition under 694cb93a386Sopenharmony_ci// non-linear transformations. 695cb93a386Sopenharmony_cistatic skif::ParameterSpace<SkPoint> compute_decomposition_center( 696cb93a386Sopenharmony_ci const SkMatrix& dstToLocal, 697cb93a386Sopenharmony_ci const skif::ParameterSpace<SkRect>* contentBounds, 698cb93a386Sopenharmony_ci const skif::DeviceSpace<SkIRect>& targetOutput) { 699cb93a386Sopenharmony_ci // Will use the inverse and center of the device bounds if the content bounds aren't provided. 700cb93a386Sopenharmony_ci SkRect rect = contentBounds ? SkRect(*contentBounds) : SkRect::Make(SkIRect(targetOutput)); 701cb93a386Sopenharmony_ci SkPoint center = {rect.centerX(), rect.centerY()}; 702cb93a386Sopenharmony_ci if (!contentBounds) { 703cb93a386Sopenharmony_ci // Theoretically, the inverse transform could put center's homogeneous coord behind W = 0, 704cb93a386Sopenharmony_ci // but that case is handled automatically in Mapping::decomposeCTM later. 705cb93a386Sopenharmony_ci dstToLocal.mapPoints(¢er, 1); 706cb93a386Sopenharmony_ci } 707cb93a386Sopenharmony_ci 708cb93a386Sopenharmony_ci return skif::ParameterSpace<SkPoint>(center); 709cb93a386Sopenharmony_ci} 710cb93a386Sopenharmony_ci 711cb93a386Sopenharmony_ci// Compute suitable transformations and layer bounds for a new layer that will be used as the source 712cb93a386Sopenharmony_ci// input into 'filter' before being drawn into 'dst' via the returned skif::Mapping. 713cb93a386Sopenharmony_ci// Null filters are permitted and act as the identity. The returned mapping will be compatible with 714cb93a386Sopenharmony_ci// the image filter. 715cb93a386Sopenharmony_ci// 716cb93a386Sopenharmony_ci// Returns an empty rect if the layer wouldn't draw anything after filtering. 717cb93a386Sopenharmony_cistatic std::pair<skif::Mapping, skif::LayerSpace<SkIRect>> get_layer_mapping_and_bounds( 718cb93a386Sopenharmony_ci const SkImageFilter* filter, 719cb93a386Sopenharmony_ci const SkMatrix& localToDst, 720cb93a386Sopenharmony_ci const skif::DeviceSpace<SkIRect>& targetOutput, 721cb93a386Sopenharmony_ci const skif::ParameterSpace<SkRect>* contentBounds = nullptr, 722cb93a386Sopenharmony_ci bool mustCoverDst = true, 723cb93a386Sopenharmony_ci SkScalar scaleFactor = 1.0f) { 724cb93a386Sopenharmony_ci auto failedMapping = []() { 725cb93a386Sopenharmony_ci return std::make_pair<skif::Mapping, skif::LayerSpace<SkIRect>>( 726cb93a386Sopenharmony_ci {}, skif::LayerSpace<SkIRect>::Empty()); 727cb93a386Sopenharmony_ci }; 728cb93a386Sopenharmony_ci 729cb93a386Sopenharmony_ci SkMatrix dstToLocal; 730cb93a386Sopenharmony_ci if (!localToDst.isFinite() || 731cb93a386Sopenharmony_ci !localToDst.invert(&dstToLocal)) { 732cb93a386Sopenharmony_ci return failedMapping(); 733cb93a386Sopenharmony_ci } 734cb93a386Sopenharmony_ci 735cb93a386Sopenharmony_ci skif::ParameterSpace<SkPoint> center = 736cb93a386Sopenharmony_ci compute_decomposition_center(dstToLocal, contentBounds, targetOutput); 737cb93a386Sopenharmony_ci // *after* possibly getting a representative point from the provided content bounds, it might 738cb93a386Sopenharmony_ci // be necessary to discard the bounds for subsequent layer calculations. 739cb93a386Sopenharmony_ci if (mustCoverDst) { 740cb93a386Sopenharmony_ci contentBounds = nullptr; 741cb93a386Sopenharmony_ci } 742cb93a386Sopenharmony_ci 743cb93a386Sopenharmony_ci // Determine initial mapping and a reasonable maximum dimension to prevent layer-to-device 744cb93a386Sopenharmony_ci // transforms with perspective and skew from triggering excessive buffer allocations. 745cb93a386Sopenharmony_ci skif::Mapping mapping; 746cb93a386Sopenharmony_ci if (!mapping.decomposeCTM(localToDst, filter, center)) { 747cb93a386Sopenharmony_ci return failedMapping(); 748cb93a386Sopenharmony_ci } 749cb93a386Sopenharmony_ci // Push scale factor into layer matrix and device matrix (net no change, but the layer will have 750cb93a386Sopenharmony_ci // its resolution adjusted in comparison to the final device). 751cb93a386Sopenharmony_ci if (scaleFactor != 1.0f && 752cb93a386Sopenharmony_ci !mapping.adjustLayerSpace(SkMatrix::Scale(scaleFactor, scaleFactor))) { 753cb93a386Sopenharmony_ci return failedMapping(); 754cb93a386Sopenharmony_ci } 755cb93a386Sopenharmony_ci 756cb93a386Sopenharmony_ci // Perspective and skew could exceed this since mapping.deviceToLayer(targetOutput) is 757cb93a386Sopenharmony_ci // theoretically unbounded under those conditions. Under a 45 degree rotation, a layer needs to 758cb93a386Sopenharmony_ci // be 2X larger per side of the prior device in order to fully cover it. We use the max of that 759cb93a386Sopenharmony_ci // and 2048 for a reasonable upper limit (this allows small layers under extreme transforms to 760cb93a386Sopenharmony_ci // use more relative resolution than a larger layer). 761cb93a386Sopenharmony_ci static const int kMinDimThreshold = 2048; 762cb93a386Sopenharmony_ci int maxLayerDim = std::max(Sk64_pin_to_s32(2 * std::max(SkIRect(targetOutput).width64(), 763cb93a386Sopenharmony_ci SkIRect(targetOutput).height64())), 764cb93a386Sopenharmony_ci kMinDimThreshold); 765cb93a386Sopenharmony_ci 766cb93a386Sopenharmony_ci skif::LayerSpace<SkIRect> layerBounds; 767cb93a386Sopenharmony_ci if (filter) { 768cb93a386Sopenharmony_ci layerBounds = as_IFB(filter)->getInputBounds(mapping, targetOutput, contentBounds); 769cb93a386Sopenharmony_ci // When a filter is involved, the layer size may be larger than the default maxLayerDim due 770cb93a386Sopenharmony_ci // to required inputs for filters (e.g. a displacement map with a large radius). 771cb93a386Sopenharmony_ci if (layerBounds.width() > maxLayerDim || layerBounds.height() > maxLayerDim) { 772cb93a386Sopenharmony_ci skif::Mapping idealMapping(SkMatrix::I(), mapping.layerMatrix()); 773cb93a386Sopenharmony_ci auto idealLayerBounds = as_IFB(filter)->getInputBounds(idealMapping, targetOutput, 774cb93a386Sopenharmony_ci contentBounds); 775cb93a386Sopenharmony_ci maxLayerDim = std::max(std::max(idealLayerBounds.width(), idealLayerBounds.height()), 776cb93a386Sopenharmony_ci maxLayerDim); 777cb93a386Sopenharmony_ci } 778cb93a386Sopenharmony_ci } else { 779cb93a386Sopenharmony_ci layerBounds = mapping.deviceToLayer(targetOutput); 780cb93a386Sopenharmony_ci if (contentBounds) { 781cb93a386Sopenharmony_ci // For better or for worse, user bounds currently act as a hard clip on the layer's 782cb93a386Sopenharmony_ci // extent (i.e., they implement the CSS filter-effects 'filter region' feature). 783cb93a386Sopenharmony_ci skif::LayerSpace<SkIRect> knownBounds = mapping.paramToLayer(*contentBounds).roundOut(); 784cb93a386Sopenharmony_ci if (!layerBounds.intersect(knownBounds)) { 785cb93a386Sopenharmony_ci return failedMapping(); 786cb93a386Sopenharmony_ci } 787cb93a386Sopenharmony_ci } 788cb93a386Sopenharmony_ci } 789cb93a386Sopenharmony_ci 790cb93a386Sopenharmony_ci if (layerBounds.width() > maxLayerDim || layerBounds.height() > maxLayerDim) { 791cb93a386Sopenharmony_ci skif::LayerSpace<SkIRect> newLayerBounds( 792cb93a386Sopenharmony_ci SkIRect::MakeWH(std::min(layerBounds.width(), maxLayerDim), 793cb93a386Sopenharmony_ci std::min(layerBounds.height(), maxLayerDim))); 794cb93a386Sopenharmony_ci SkMatrix adjust = SkMatrix::MakeRectToRect(SkRect::Make(SkIRect(layerBounds)), 795cb93a386Sopenharmony_ci SkRect::Make(SkIRect(newLayerBounds)), 796cb93a386Sopenharmony_ci SkMatrix::kFill_ScaleToFit); 797cb93a386Sopenharmony_ci if (!mapping.adjustLayerSpace(adjust)) { 798cb93a386Sopenharmony_ci return failedMapping(); 799cb93a386Sopenharmony_ci } else { 800cb93a386Sopenharmony_ci layerBounds = newLayerBounds; 801cb93a386Sopenharmony_ci } 802cb93a386Sopenharmony_ci } 803cb93a386Sopenharmony_ci 804cb93a386Sopenharmony_ci return {mapping, layerBounds}; 805cb93a386Sopenharmony_ci} 806cb93a386Sopenharmony_ci 807cb93a386Sopenharmony_cistatic SkImageInfo make_layer_info(const SkImageInfo& prev, int w, int h, bool f16) { 808cb93a386Sopenharmony_ci SkColorType ct = f16 ? SkColorType::kRGBA_F16_SkColorType : prev.colorType(); 809cb93a386Sopenharmony_ci if (!f16 && 810cb93a386Sopenharmony_ci prev.bytesPerPixel() <= 4 && 811cb93a386Sopenharmony_ci prev.colorType() != kRGBA_8888_SkColorType && 812cb93a386Sopenharmony_ci prev.colorType() != kBGRA_8888_SkColorType) { 813cb93a386Sopenharmony_ci // "Upgrade" A8, G8, 565, 4444, 1010102, 101010x, and 888x to 8888, 814cb93a386Sopenharmony_ci // ensuring plenty of alpha bits for the layer, perhaps losing some color bits in return. 815cb93a386Sopenharmony_ci ct = kN32_SkColorType; 816cb93a386Sopenharmony_ci } 817cb93a386Sopenharmony_ci return SkImageInfo::Make(w, h, ct, kPremul_SkAlphaType, prev.refColorSpace()); 818cb93a386Sopenharmony_ci} 819cb93a386Sopenharmony_ci 820cb93a386Sopenharmony_cistatic bool draw_layer_as_sprite(const SkMatrix& matrix, const SkISize& size) { 821cb93a386Sopenharmony_ci // Assume anti-aliasing and highest valid filter mode (linear) for drawing layers and image 822cb93a386Sopenharmony_ci // filters. If the layer can be drawn as a sprite, these can be downgraded. 823cb93a386Sopenharmony_ci SkPaint paint; 824cb93a386Sopenharmony_ci paint.setAntiAlias(true); 825cb93a386Sopenharmony_ci SkSamplingOptions sampling{SkFilterMode::kLinear}; 826cb93a386Sopenharmony_ci return SkTreatAsSprite(matrix, size, sampling, paint); 827cb93a386Sopenharmony_ci} 828cb93a386Sopenharmony_ci 829cb93a386Sopenharmony_civoid SkCanvas::internalDrawDeviceWithFilter(SkBaseDevice* src, 830cb93a386Sopenharmony_ci SkBaseDevice* dst, 831cb93a386Sopenharmony_ci const SkImageFilter* filter, 832cb93a386Sopenharmony_ci const SkPaint& paint, 833cb93a386Sopenharmony_ci DeviceCompatibleWithFilter compat, 834cb93a386Sopenharmony_ci SkScalar scaleFactor) { 835cb93a386Sopenharmony_ci check_drawdevice_colorspaces(dst->imageInfo().colorSpace(), 836cb93a386Sopenharmony_ci src->imageInfo().colorSpace()); 837cb93a386Sopenharmony_ci 838cb93a386Sopenharmony_ci // 'filter' sees the src device's buffer as the implicit input image, and processes the image 839cb93a386Sopenharmony_ci // in this device space (referred to as the "layer" space). However, the filter 840cb93a386Sopenharmony_ci // parameters need to respect the current matrix, which is not necessarily the local matrix that 841cb93a386Sopenharmony_ci // was set on 'src' (e.g. because we've popped src off the stack already). 842cb93a386Sopenharmony_ci // TODO (michaelludwig): Stay in SkM44 once skif::Mapping supports SkM44 instead of SkMatrix. 843cb93a386Sopenharmony_ci SkMatrix localToSrc = (src->globalToDevice() * fMCRec->fMatrix).asM33(); 844cb93a386Sopenharmony_ci SkISize srcDims = src->imageInfo().dimensions(); 845cb93a386Sopenharmony_ci 846cb93a386Sopenharmony_ci // Whether or not we need to make a transformed tmp image from 'src', and what that transform is 847cb93a386Sopenharmony_ci bool needsIntermediateImage = false; 848cb93a386Sopenharmony_ci SkMatrix srcToIntermediate; 849cb93a386Sopenharmony_ci 850cb93a386Sopenharmony_ci skif::Mapping mapping; 851cb93a386Sopenharmony_ci skif::LayerSpace<SkIRect> requiredInput; 852cb93a386Sopenharmony_ci if (compat == DeviceCompatibleWithFilter::kYes) { 853cb93a386Sopenharmony_ci // Just use the relative transform from src to dst and the src's whole image, since 854cb93a386Sopenharmony_ci // internalSaveLayer should have already determined what was necessary. 855cb93a386Sopenharmony_ci SkASSERT(scaleFactor == 1.0f); 856cb93a386Sopenharmony_ci mapping = skif::Mapping(src->getRelativeTransform(*dst), localToSrc); 857cb93a386Sopenharmony_ci requiredInput = skif::LayerSpace<SkIRect>(SkIRect::MakeSize(srcDims)); 858cb93a386Sopenharmony_ci SkASSERT(!requiredInput.isEmpty()); 859cb93a386Sopenharmony_ci } else { 860cb93a386Sopenharmony_ci // Compute the image filter mapping by decomposing the local->device matrix of dst and 861cb93a386Sopenharmony_ci // re-determining the required input. 862cb93a386Sopenharmony_ci std::tie(mapping, requiredInput) = get_layer_mapping_and_bounds( 863cb93a386Sopenharmony_ci filter, dst->localToDevice(), skif::DeviceSpace<SkIRect>(dst->devClipBounds()), 864cb93a386Sopenharmony_ci nullptr, true, SkTPin(scaleFactor, 0.f, 1.f)); 865cb93a386Sopenharmony_ci if (requiredInput.isEmpty()) { 866cb93a386Sopenharmony_ci return; 867cb93a386Sopenharmony_ci } 868cb93a386Sopenharmony_ci 869cb93a386Sopenharmony_ci // The above mapping transforms from local to dst's device space, where the layer space 870cb93a386Sopenharmony_ci // represents the intermediate buffer. Now we need to determine the transform from src to 871cb93a386Sopenharmony_ci // intermediate to prepare the input to the filter. 872cb93a386Sopenharmony_ci if (!localToSrc.invert(&srcToIntermediate)) { 873cb93a386Sopenharmony_ci return; 874cb93a386Sopenharmony_ci } 875cb93a386Sopenharmony_ci srcToIntermediate.postConcat(mapping.layerMatrix()); 876cb93a386Sopenharmony_ci if (draw_layer_as_sprite(srcToIntermediate, srcDims)) { 877cb93a386Sopenharmony_ci // src differs from intermediate by just an integer translation, so it can be applied 878cb93a386Sopenharmony_ci // automatically when taking a subset of src if we update the mapping. 879cb93a386Sopenharmony_ci skif::LayerSpace<SkIPoint> srcOrigin({(int) srcToIntermediate.getTranslateX(), 880cb93a386Sopenharmony_ci (int) srcToIntermediate.getTranslateY()}); 881cb93a386Sopenharmony_ci mapping.applyOrigin(srcOrigin); 882cb93a386Sopenharmony_ci requiredInput.offset(-srcOrigin); 883cb93a386Sopenharmony_ci } else { 884cb93a386Sopenharmony_ci // The contents of 'src' will be drawn to an intermediate buffer using srcToIntermediate 885cb93a386Sopenharmony_ci // and that buffer will be the input to the image filter. 886cb93a386Sopenharmony_ci needsIntermediateImage = true; 887cb93a386Sopenharmony_ci } 888cb93a386Sopenharmony_ci } 889cb93a386Sopenharmony_ci 890cb93a386Sopenharmony_ci sk_sp<SkSpecialImage> filterInput; 891cb93a386Sopenharmony_ci if (!needsIntermediateImage) { 892cb93a386Sopenharmony_ci // The src device can be snapped directly 893cb93a386Sopenharmony_ci skif::LayerSpace<SkIRect> srcSubset(SkIRect::MakeSize(srcDims)); 894cb93a386Sopenharmony_ci if (srcSubset.intersect(requiredInput)) { 895cb93a386Sopenharmony_ci filterInput = src->snapSpecial(SkIRect(srcSubset)); 896cb93a386Sopenharmony_ci 897cb93a386Sopenharmony_ci // TODO: For now image filter input images need to have a (0,0) origin. The required 898cb93a386Sopenharmony_ci // input's top left has been baked into srcSubset so we use that as the image origin. 899cb93a386Sopenharmony_ci mapping.applyOrigin(srcSubset.topLeft()); 900cb93a386Sopenharmony_ci } 901cb93a386Sopenharmony_ci } else { 902cb93a386Sopenharmony_ci // We need to produce a temporary image that is equivalent to 'src' but transformed to 903cb93a386Sopenharmony_ci // a coordinate space compatible with the image filter 904cb93a386Sopenharmony_ci 905cb93a386Sopenharmony_ci // TODO: If the srcToIntermediate is scale+translate, can we use the framebuffer blit 906cb93a386Sopenharmony_ci // extensions to handle doing the copy and scale at the same time? 907cb93a386Sopenharmony_ci 908cb93a386Sopenharmony_ci SkASSERT(compat == DeviceCompatibleWithFilter::kUnknown); 909cb93a386Sopenharmony_ci SkRect srcRect; 910cb93a386Sopenharmony_ci if (!SkMatrixPriv::InverseMapRect(srcToIntermediate, &srcRect, 911cb93a386Sopenharmony_ci SkRect::Make(SkIRect(requiredInput)))) { 912cb93a386Sopenharmony_ci return; 913cb93a386Sopenharmony_ci } 914cb93a386Sopenharmony_ci 915cb93a386Sopenharmony_ci SkIRect srcSubset = srcRect.roundOut(); 916cb93a386Sopenharmony_ci sk_sp<SkSpecialImage> srcImage; 917cb93a386Sopenharmony_ci if (srcSubset.intersect(SkIRect::MakeSize(srcDims)) && 918cb93a386Sopenharmony_ci (srcImage = src->snapSpecial(srcSubset))) { 919cb93a386Sopenharmony_ci // Make a new surface and draw 'srcImage' into it with the srcToIntermediate transform 920cb93a386Sopenharmony_ci // to produce the final input image for the filter 921cb93a386Sopenharmony_ci SkBaseDevice::CreateInfo info(make_layer_info(src->imageInfo(), requiredInput.width(), 922cb93a386Sopenharmony_ci requiredInput.height(), false), 923cb93a386Sopenharmony_ci SkPixelGeometry::kUnknown_SkPixelGeometry, 924cb93a386Sopenharmony_ci SkBaseDevice::TileUsage::kNever_TileUsage, 925cb93a386Sopenharmony_ci false, fAllocator.get()); 926cb93a386Sopenharmony_ci sk_sp<SkBaseDevice> intermediateDevice(src->onCreateDevice(info, &paint)); 927cb93a386Sopenharmony_ci if (!intermediateDevice) { 928cb93a386Sopenharmony_ci return; 929cb93a386Sopenharmony_ci } 930cb93a386Sopenharmony_ci intermediateDevice->setOrigin(SkM44(srcToIntermediate), 931cb93a386Sopenharmony_ci requiredInput.left(), requiredInput.top()); 932cb93a386Sopenharmony_ci 933cb93a386Sopenharmony_ci SkMatrix offsetLocalToDevice = intermediateDevice->localToDevice(); 934cb93a386Sopenharmony_ci offsetLocalToDevice.preTranslate(srcSubset.left(), srcSubset.top()); 935cb93a386Sopenharmony_ci // We draw with non-AA bilinear since we cover the destination but definitely don't have 936cb93a386Sopenharmony_ci // a pixel-aligned transform. 937cb93a386Sopenharmony_ci intermediateDevice->drawSpecial(srcImage.get(), offsetLocalToDevice, 938cb93a386Sopenharmony_ci SkSamplingOptions{SkFilterMode::kLinear}, {}); 939cb93a386Sopenharmony_ci filterInput = intermediateDevice->snapSpecial(); 940cb93a386Sopenharmony_ci 941cb93a386Sopenharmony_ci // TODO: Like the non-intermediate case, we need to apply the image origin. 942cb93a386Sopenharmony_ci mapping.applyOrigin(requiredInput.topLeft()); 943cb93a386Sopenharmony_ci } 944cb93a386Sopenharmony_ci } 945cb93a386Sopenharmony_ci 946cb93a386Sopenharmony_ci if (filterInput) { 947cb93a386Sopenharmony_ci const bool use_nn = draw_layer_as_sprite(mapping.deviceMatrix(), 948cb93a386Sopenharmony_ci filterInput->subset().size()); 949cb93a386Sopenharmony_ci SkSamplingOptions sampling{use_nn ? SkFilterMode::kNearest : SkFilterMode::kLinear}; 950cb93a386Sopenharmony_ci if (filter) { 951cb93a386Sopenharmony_ci dst->drawFilteredImage(mapping, filterInput.get(), filter, sampling, paint); 952cb93a386Sopenharmony_ci } else { 953cb93a386Sopenharmony_ci dst->drawSpecial(filterInput.get(), mapping.deviceMatrix(), sampling, paint); 954cb93a386Sopenharmony_ci } 955cb93a386Sopenharmony_ci } 956cb93a386Sopenharmony_ci} 957cb93a386Sopenharmony_ci 958cb93a386Sopenharmony_ci// This is similar to image_to_color_filter used by AutoLayerForImageFilter, but with key changes: 959cb93a386Sopenharmony_ci// - image_to_color_filter requires the entire image filter DAG to be represented as a color filter 960cb93a386Sopenharmony_ci// that does not affect transparent black (SkImageFilter::asAColorFilter) 961cb93a386Sopenharmony_ci// - when that is met, the image filter's CF is composed around any CF that was on the draw's paint 962cb93a386Sopenharmony_ci// since for a draw, the color filtering happens before any image filtering 963cb93a386Sopenharmony_ci// - optimize_layer_filter only applies to the last node and does not care about transparent black 964cb93a386Sopenharmony_ci// since a layer is being made regardless (SkImageFilter::isColorFilterNode) 965cb93a386Sopenharmony_ci// - any extracted CF is composed inside the restore paint's CF because image filters are evaluated 966cb93a386Sopenharmony_ci// before the color filter of a restore paint for layers. 967cb93a386Sopenharmony_ci// 968cb93a386Sopenharmony_ci// Assumes that 'filter', and thus its inputs, will remain owned by the caller. Modifies 'paint' 969cb93a386Sopenharmony_ci// to have the updated color filter and returns the image filter to evaluate on restore. 970cb93a386Sopenharmony_ci// 971cb93a386Sopenharmony_ci// FIXME: skbug.com/12083 - we modify 'coversDevice' here because for now, only the color filter 972cb93a386Sopenharmony_ci// produced from an image filter node is checked for affecting transparent black, even though it's 973cb93a386Sopenharmony_ci// better in the long run to have any CF that affects transparent black expand to the clip. 974cb93a386Sopenharmony_cistatic const SkImageFilter* optimize_layer_filter(const SkImageFilter* filter, SkPaint* paint, 975cb93a386Sopenharmony_ci bool* coversDevice=nullptr) { 976cb93a386Sopenharmony_ci SkASSERT(paint); 977cb93a386Sopenharmony_ci SkColorFilter* cf; 978cb93a386Sopenharmony_ci if (filter && filter->isColorFilterNode(&cf)) { 979cb93a386Sopenharmony_ci sk_sp<SkColorFilter> inner(cf); 980cb93a386Sopenharmony_ci if (paint->getAlphaf() < 1.f) { 981cb93a386Sopenharmony_ci // The paint's alpha is applied after the image filter but before the paint's color 982cb93a386Sopenharmony_ci // filter. If there is transparency, we have to apply it between the two filters. 983cb93a386Sopenharmony_ci // FIXME: The Blend CF should allow composing directly at construction. 984cb93a386Sopenharmony_ci inner = SkColorFilters::Compose( 985cb93a386Sopenharmony_ci SkColorFilters::Blend(/* src */ paint->getColor(), SkBlendMode::kDstIn), 986cb93a386Sopenharmony_ci /* dst */ std::move(inner)); 987cb93a386Sopenharmony_ci paint->setAlphaf(1.f); 988cb93a386Sopenharmony_ci } 989cb93a386Sopenharmony_ci 990cb93a386Sopenharmony_ci // Check if the once-wrapped color filter affects transparent black *before* we combine 991cb93a386Sopenharmony_ci // it with any original color filter on the paint. 992cb93a386Sopenharmony_ci if (coversDevice) { 993cb93a386Sopenharmony_ci *coversDevice = as_CFB(inner)->affectsTransparentBlack(); 994cb93a386Sopenharmony_ci } 995cb93a386Sopenharmony_ci 996cb93a386Sopenharmony_ci paint->setColorFilter(SkColorFilters::Compose(paint->refColorFilter(), std::move(inner))); 997cb93a386Sopenharmony_ci SkASSERT(filter->countInputs() == 1); 998cb93a386Sopenharmony_ci return filter->getInput(0); 999cb93a386Sopenharmony_ci } else { 1000cb93a386Sopenharmony_ci if (coversDevice) { 1001cb93a386Sopenharmony_ci *coversDevice = false; 1002cb93a386Sopenharmony_ci } 1003cb93a386Sopenharmony_ci return filter; 1004cb93a386Sopenharmony_ci } 1005cb93a386Sopenharmony_ci} 1006cb93a386Sopenharmony_ci 1007cb93a386Sopenharmony_ci// If there is a backdrop filter, or if the restore paint has a color filter that affects 1008cb93a386Sopenharmony_ci// transparent black, then the new layer must be sized such that it covers the entire device 1009cb93a386Sopenharmony_ci// clip bounds of the prior device (otherwise edges of the temporary layer would be visible). 1010cb93a386Sopenharmony_ci// See skbug.com/8783 1011cb93a386Sopenharmony_cistatic bool must_cover_prior_device(const SkImageFilter* backdrop, 1012cb93a386Sopenharmony_ci const SkPaint& restorePaint) { 1013cb93a386Sopenharmony_ci // FIXME(michaelludwig) - see skbug.com/12083, once clients do not depend on user bounds for 1014cb93a386Sopenharmony_ci // clipping a layer visually, we can respect the fact that the color filter affects transparent 1015cb93a386Sopenharmony_ci // black and should cover the device. 1016cb93a386Sopenharmony_ci return SkToBool(backdrop); // || 1017cb93a386Sopenharmony_ci // (restorePaint.getColorFilter() && 1018cb93a386Sopenharmony_ci // as_CFB(restorePaint.getColorFilter())->affectsTransparentBlack()); 1019cb93a386Sopenharmony_ci} 1020cb93a386Sopenharmony_ci 1021cb93a386Sopenharmony_civoid SkCanvas::internalSaveLayer(const SaveLayerRec& rec, SaveLayerStrategy strategy) { 1022cb93a386Sopenharmony_ci TRACE_EVENT0("skia", TRACE_FUNC); 1023cb93a386Sopenharmony_ci // Do this before we create the layer. We don't call the public save() since that would invoke a 1024cb93a386Sopenharmony_ci // possibly overridden virtual. 1025cb93a386Sopenharmony_ci this->internalSave(); 1026cb93a386Sopenharmony_ci 1027cb93a386Sopenharmony_ci if (this->isClipEmpty()) { 1028cb93a386Sopenharmony_ci // Early out if the layer wouldn't draw anything 1029cb93a386Sopenharmony_ci return; 1030cb93a386Sopenharmony_ci } 1031cb93a386Sopenharmony_ci 1032cb93a386Sopenharmony_ci // Build up the paint for restoring the layer, taking only the pieces of rec.fPaint that are 1033cb93a386Sopenharmony_ci // relevant. Filtering is automatically chosen in internalDrawDeviceWithFilter based on the 1034cb93a386Sopenharmony_ci // device's coordinate space. 1035cb93a386Sopenharmony_ci SkPaint restorePaint(rec.fPaint ? *rec.fPaint : SkPaint()); 1036cb93a386Sopenharmony_ci restorePaint.setMaskFilter(nullptr); // mask filters are ignored for saved layers 1037cb93a386Sopenharmony_ci restorePaint.setImageFilter(nullptr); // the image filter is held separately 1038cb93a386Sopenharmony_ci // Smooth non-axis-aligned layer edges; this automatically downgrades to non-AA for aligned 1039cb93a386Sopenharmony_ci // layer restores. This is done to match legacy behavior where the post-applied MatrixTransform 1040cb93a386Sopenharmony_ci // bilerp also smoothed cropped edges. See skbug.com/11252 1041cb93a386Sopenharmony_ci restorePaint.setAntiAlias(true); 1042cb93a386Sopenharmony_ci 1043cb93a386Sopenharmony_ci bool optimizedCFAffectsTransparent; 1044cb93a386Sopenharmony_ci const SkImageFilter* filter = optimize_layer_filter( 1045cb93a386Sopenharmony_ci rec.fPaint ? rec.fPaint->getImageFilter() : nullptr, &restorePaint, 1046cb93a386Sopenharmony_ci &optimizedCFAffectsTransparent); 1047cb93a386Sopenharmony_ci 1048cb93a386Sopenharmony_ci // Size the new layer relative to the prior device, which may already be aligned for filters. 1049cb93a386Sopenharmony_ci SkBaseDevice* priorDevice = this->topDevice(); 1050cb93a386Sopenharmony_ci skif::Mapping newLayerMapping; 1051cb93a386Sopenharmony_ci skif::LayerSpace<SkIRect> layerBounds; 1052cb93a386Sopenharmony_ci std::tie(newLayerMapping, layerBounds) = get_layer_mapping_and_bounds( 1053cb93a386Sopenharmony_ci filter, priorDevice->localToDevice(), 1054cb93a386Sopenharmony_ci skif::DeviceSpace<SkIRect>(priorDevice->devClipBounds()), 1055cb93a386Sopenharmony_ci skif::ParameterSpace<SkRect>::Optional(rec.fBounds), 1056cb93a386Sopenharmony_ci must_cover_prior_device(rec.fBackdrop, restorePaint) || optimizedCFAffectsTransparent); 1057cb93a386Sopenharmony_ci 1058cb93a386Sopenharmony_ci auto abortLayer = [this]() { 1059cb93a386Sopenharmony_ci // The filtered content would not draw anything, or the new device space has an invalid 1060cb93a386Sopenharmony_ci // coordinate system, in which case we mark the current top device as empty so that nothing 1061cb93a386Sopenharmony_ci // draws until the canvas is restored past this saveLayer. 1062cb93a386Sopenharmony_ci AutoUpdateQRBounds aqr(this); 1063cb93a386Sopenharmony_ci this->topDevice()->clipRect(SkRect::MakeEmpty(), SkClipOp::kIntersect, /* aa */ false); 1064cb93a386Sopenharmony_ci }; 1065cb93a386Sopenharmony_ci 1066cb93a386Sopenharmony_ci if (layerBounds.isEmpty()) { 1067cb93a386Sopenharmony_ci abortLayer(); 1068cb93a386Sopenharmony_ci return; 1069cb93a386Sopenharmony_ci } 1070cb93a386Sopenharmony_ci 1071cb93a386Sopenharmony_ci sk_sp<SkBaseDevice> newDevice; 1072cb93a386Sopenharmony_ci if (strategy == kFullLayer_SaveLayerStrategy) { 1073cb93a386Sopenharmony_ci SkASSERT(!layerBounds.isEmpty()); 1074cb93a386Sopenharmony_ci SkImageInfo info = make_layer_info(priorDevice->imageInfo(), 1075cb93a386Sopenharmony_ci layerBounds.width(), layerBounds.height(), 1076cb93a386Sopenharmony_ci SkToBool(rec.fSaveLayerFlags & kF16ColorType)); 1077cb93a386Sopenharmony_ci if (rec.fSaveLayerFlags & kF16ColorType) { 1078cb93a386Sopenharmony_ci info = info.makeColorType(kRGBA_F16_SkColorType); 1079cb93a386Sopenharmony_ci } 1080cb93a386Sopenharmony_ci SkASSERT(info.alphaType() != kOpaque_SkAlphaType); 1081cb93a386Sopenharmony_ci 1082cb93a386Sopenharmony_ci SkPixelGeometry geo = rec.fSaveLayerFlags & kPreserveLCDText_SaveLayerFlag 1083cb93a386Sopenharmony_ci ? fProps.pixelGeometry() 1084cb93a386Sopenharmony_ci : kUnknown_SkPixelGeometry; 1085cb93a386Sopenharmony_ci const bool trackCoverage = SkToBool( 1086cb93a386Sopenharmony_ci rec.fSaveLayerFlags & kMaskAgainstCoverage_EXPERIMENTAL_DONT_USE_SaveLayerFlag); 1087cb93a386Sopenharmony_ci const auto createInfo = SkBaseDevice::CreateInfo(info, geo, SkBaseDevice::kNever_TileUsage, 1088cb93a386Sopenharmony_ci trackCoverage, fAllocator.get()); 1089cb93a386Sopenharmony_ci // Use the original paint as a hint so that it includes the image filter 1090cb93a386Sopenharmony_ci newDevice.reset(priorDevice->onCreateDevice(createInfo, rec.fPaint)); 1091cb93a386Sopenharmony_ci } 1092cb93a386Sopenharmony_ci 1093cb93a386Sopenharmony_ci bool initBackdrop = (rec.fSaveLayerFlags & kInitWithPrevious_SaveLayerFlag) || rec.fBackdrop; 1094cb93a386Sopenharmony_ci if (!newDevice) { 1095cb93a386Sopenharmony_ci // Either we weren't meant to allocate a full layer, or the full layer creation failed. 1096cb93a386Sopenharmony_ci // Using an explicit NoPixelsDevice lets us reflect what the layer state would have been 1097cb93a386Sopenharmony_ci // on success (or kFull_LayerStrategy) while squashing draw calls that target something that 1098cb93a386Sopenharmony_ci // doesn't exist. 1099cb93a386Sopenharmony_ci newDevice = sk_make_sp<SkNoPixelsDevice>(SkIRect::MakeWH(layerBounds.width(), 1100cb93a386Sopenharmony_ci layerBounds.height()), 1101cb93a386Sopenharmony_ci fProps, this->imageInfo().refColorSpace()); 1102cb93a386Sopenharmony_ci initBackdrop = false; 1103cb93a386Sopenharmony_ci } 1104cb93a386Sopenharmony_ci 1105cb93a386Sopenharmony_ci // Configure device to match determined mapping for any image filters. 1106cb93a386Sopenharmony_ci // The setDeviceCoordinateSystem applies the prior device's global transform since 1107cb93a386Sopenharmony_ci // 'newLayerMapping' only defines the transforms between the two devices and it must be updated 1108cb93a386Sopenharmony_ci // to the global coordinate system. 1109cb93a386Sopenharmony_ci newDevice->setMarkerStack(fMarkerStack.get()); 1110cb93a386Sopenharmony_ci if (!newDevice->setDeviceCoordinateSystem(priorDevice->deviceToGlobal() * 1111cb93a386Sopenharmony_ci SkM44(newLayerMapping.deviceMatrix()), 1112cb93a386Sopenharmony_ci SkM44(newLayerMapping.layerMatrix()), 1113cb93a386Sopenharmony_ci layerBounds.left(), layerBounds.top())) { 1114cb93a386Sopenharmony_ci // If we made it this far and the coordinate system is invalid, we most likely had a valid 1115cb93a386Sopenharmony_ci // mapping until being combined with the previous device-to-global matrix, at which point 1116cb93a386Sopenharmony_ci // it overflowed or floating point rounding caused it to no longer be invertible. There's 1117cb93a386Sopenharmony_ci // not much we can do but clean up the layer and mark the clip as empty. This tends to come 1118cb93a386Sopenharmony_ci // up in fuzzer-generated inputs, so this policy is not unreasonable and helps avoids UB. 1119cb93a386Sopenharmony_ci newDevice = nullptr; 1120cb93a386Sopenharmony_ci abortLayer(); 1121cb93a386Sopenharmony_ci return; 1122cb93a386Sopenharmony_ci } 1123cb93a386Sopenharmony_ci 1124cb93a386Sopenharmony_ci if (initBackdrop) { 1125cb93a386Sopenharmony_ci SkPaint backdropPaint; 1126cb93a386Sopenharmony_ci const SkImageFilter* backdropFilter = optimize_layer_filter(rec.fBackdrop, &backdropPaint); 1127cb93a386Sopenharmony_ci // The new device was constructed to be compatible with 'filter', not necessarily 1128cb93a386Sopenharmony_ci // 'rec.fBackdrop', so allow DrawDeviceWithFilter to transform the prior device contents 1129cb93a386Sopenharmony_ci // if necessary to evaluate the backdrop filter. If no filters are involved, then the 1130cb93a386Sopenharmony_ci // devices differ by integer translations and are always compatible. 1131cb93a386Sopenharmony_ci bool scaleBackdrop = rec.fExperimentalBackdropScale != 1.0f; 1132cb93a386Sopenharmony_ci auto compat = (filter || backdropFilter || scaleBackdrop) 1133cb93a386Sopenharmony_ci ? DeviceCompatibleWithFilter::kUnknown : DeviceCompatibleWithFilter::kYes; 1134cb93a386Sopenharmony_ci this->internalDrawDeviceWithFilter(priorDevice, // src 1135cb93a386Sopenharmony_ci newDevice.get(), // dst 1136cb93a386Sopenharmony_ci backdropFilter, 1137cb93a386Sopenharmony_ci backdropPaint, 1138cb93a386Sopenharmony_ci compat, 1139cb93a386Sopenharmony_ci rec.fExperimentalBackdropScale); 1140cb93a386Sopenharmony_ci } 1141cb93a386Sopenharmony_ci 1142cb93a386Sopenharmony_ci fMCRec->newLayer(std::move(newDevice), sk_ref_sp(filter), restorePaint); 1143cb93a386Sopenharmony_ci fQuickRejectBounds = this->computeDeviceClipBounds(); 1144cb93a386Sopenharmony_ci} 1145cb93a386Sopenharmony_ci 1146cb93a386Sopenharmony_ciint SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) { 1147cb93a386Sopenharmony_ci if (0xFF == alpha) { 1148cb93a386Sopenharmony_ci return this->saveLayer(bounds, nullptr); 1149cb93a386Sopenharmony_ci } else { 1150cb93a386Sopenharmony_ci SkPaint tmpPaint; 1151cb93a386Sopenharmony_ci tmpPaint.setAlpha(alpha); 1152cb93a386Sopenharmony_ci return this->saveLayer(bounds, &tmpPaint); 1153cb93a386Sopenharmony_ci } 1154cb93a386Sopenharmony_ci} 1155cb93a386Sopenharmony_ci 1156cb93a386Sopenharmony_civoid SkCanvas::internalSaveBehind(const SkRect* localBounds) { 1157cb93a386Sopenharmony_ci SkBaseDevice* device = this->topDevice(); 1158cb93a386Sopenharmony_ci 1159cb93a386Sopenharmony_ci // Map the local bounds into the top device's coordinate space (this is not 1160cb93a386Sopenharmony_ci // necessarily the full global CTM transform). 1161cb93a386Sopenharmony_ci SkIRect devBounds; 1162cb93a386Sopenharmony_ci if (localBounds) { 1163cb93a386Sopenharmony_ci SkRect tmp; 1164cb93a386Sopenharmony_ci device->localToDevice().mapRect(&tmp, *localBounds); 1165cb93a386Sopenharmony_ci if (!devBounds.intersect(tmp.round(), device->devClipBounds())) { 1166cb93a386Sopenharmony_ci devBounds.setEmpty(); 1167cb93a386Sopenharmony_ci } 1168cb93a386Sopenharmony_ci } else { 1169cb93a386Sopenharmony_ci devBounds = device->devClipBounds(); 1170cb93a386Sopenharmony_ci } 1171cb93a386Sopenharmony_ci if (devBounds.isEmpty()) { 1172cb93a386Sopenharmony_ci return; 1173cb93a386Sopenharmony_ci } 1174cb93a386Sopenharmony_ci 1175cb93a386Sopenharmony_ci // This is getting the special image from the current device, which is then drawn into (both by 1176cb93a386Sopenharmony_ci // a client, and the drawClippedToSaveBehind below). Since this is not saving a layer, with its 1177cb93a386Sopenharmony_ci // own device, we need to explicitly copy the back image contents so that its original content 1178cb93a386Sopenharmony_ci // is available when we splat it back later during restore. 1179cb93a386Sopenharmony_ci auto backImage = device->snapSpecial(devBounds, /* copy */ true); 1180cb93a386Sopenharmony_ci if (!backImage) { 1181cb93a386Sopenharmony_ci return; 1182cb93a386Sopenharmony_ci } 1183cb93a386Sopenharmony_ci 1184cb93a386Sopenharmony_ci // we really need the save, so we can wack the fMCRec 1185cb93a386Sopenharmony_ci this->checkForDeferredSave(); 1186cb93a386Sopenharmony_ci 1187cb93a386Sopenharmony_ci fMCRec->fBackImage = 1188cb93a386Sopenharmony_ci std::make_unique<BackImage>(BackImage{std::move(backImage), devBounds.topLeft()}); 1189cb93a386Sopenharmony_ci 1190cb93a386Sopenharmony_ci SkPaint paint; 1191cb93a386Sopenharmony_ci paint.setBlendMode(SkBlendMode::kClear); 1192cb93a386Sopenharmony_ci this->drawClippedToSaveBehind(paint); 1193cb93a386Sopenharmony_ci} 1194cb93a386Sopenharmony_ci 1195cb93a386Sopenharmony_civoid SkCanvas::internalRestore() { 1196cb93a386Sopenharmony_ci SkASSERT(!fMCStack.empty()); 1197cb93a386Sopenharmony_ci 1198cb93a386Sopenharmony_ci // now detach these from fMCRec so we can pop(). Gets freed after its drawn 1199cb93a386Sopenharmony_ci std::unique_ptr<Layer> layer = std::move(fMCRec->fLayer); 1200cb93a386Sopenharmony_ci std::unique_ptr<BackImage> backImage = std::move(fMCRec->fBackImage); 1201cb93a386Sopenharmony_ci 1202cb93a386Sopenharmony_ci fMarkerStack->restore(fMCRec); 1203cb93a386Sopenharmony_ci 1204cb93a386Sopenharmony_ci // now do the normal restore() 1205cb93a386Sopenharmony_ci fMCRec->~MCRec(); // balanced in save() 1206cb93a386Sopenharmony_ci fMCStack.pop_back(); 1207cb93a386Sopenharmony_ci fMCRec = (MCRec*) fMCStack.back(); 1208cb93a386Sopenharmony_ci 1209cb93a386Sopenharmony_ci if (!fMCRec) { 1210cb93a386Sopenharmony_ci // This was the last record, restored during the destruction of the SkCanvas 1211cb93a386Sopenharmony_ci return; 1212cb93a386Sopenharmony_ci } 1213cb93a386Sopenharmony_ci 1214cb93a386Sopenharmony_ci this->topDevice()->restore(fMCRec->fMatrix); 1215cb93a386Sopenharmony_ci 1216cb93a386Sopenharmony_ci if (backImage) { 1217cb93a386Sopenharmony_ci SkPaint paint; 1218cb93a386Sopenharmony_ci paint.setBlendMode(SkBlendMode::kDstOver); 1219cb93a386Sopenharmony_ci this->topDevice()->drawSpecial(backImage->fImage.get(), 1220cb93a386Sopenharmony_ci SkMatrix::Translate(backImage->fLoc), 1221cb93a386Sopenharmony_ci SkSamplingOptions(), 1222cb93a386Sopenharmony_ci paint); 1223cb93a386Sopenharmony_ci } 1224cb93a386Sopenharmony_ci 1225cb93a386Sopenharmony_ci // Draw the layer's device contents into the now-current older device. We can't call public 1226cb93a386Sopenharmony_ci // draw functions since we don't want to record them. 1227cb93a386Sopenharmony_ci if (layer && !layer->fDevice->isNoPixelsDevice() && !layer->fDiscard) { 1228cb93a386Sopenharmony_ci layer->fDevice->setImmutable(); 1229cb93a386Sopenharmony_ci 1230cb93a386Sopenharmony_ci // Don't go through AutoLayerForImageFilter since device draws are so closely tied to 1231cb93a386Sopenharmony_ci // internalSaveLayer and internalRestore. 1232cb93a386Sopenharmony_ci if (this->predrawNotify()) { 1233cb93a386Sopenharmony_ci SkBaseDevice* dstDev = this->topDevice(); 1234cb93a386Sopenharmony_ci if (layer->fImageFilter) { 1235cb93a386Sopenharmony_ci this->internalDrawDeviceWithFilter(layer->fDevice.get(), // src 1236cb93a386Sopenharmony_ci dstDev, // dst 1237cb93a386Sopenharmony_ci layer->fImageFilter.get(), 1238cb93a386Sopenharmony_ci layer->fPaint, 1239cb93a386Sopenharmony_ci DeviceCompatibleWithFilter::kYes); 1240cb93a386Sopenharmony_ci } else { 1241cb93a386Sopenharmony_ci // NOTE: We don't just call internalDrawDeviceWithFilter with a null filter 1242cb93a386Sopenharmony_ci // because we want to take advantage of overridden drawDevice functions for 1243cb93a386Sopenharmony_ci // document-based devices. 1244cb93a386Sopenharmony_ci SkSamplingOptions sampling; 1245cb93a386Sopenharmony_ci dstDev->drawDevice(layer->fDevice.get(), sampling, layer->fPaint); 1246cb93a386Sopenharmony_ci } 1247cb93a386Sopenharmony_ci } 1248cb93a386Sopenharmony_ci } 1249cb93a386Sopenharmony_ci 1250cb93a386Sopenharmony_ci // Reset the clip restriction if the restore went past the save point that had added it. 1251cb93a386Sopenharmony_ci if (this->getSaveCount() < fClipRestrictionSaveCount) { 1252cb93a386Sopenharmony_ci fClipRestrictionRect.setEmpty(); 1253cb93a386Sopenharmony_ci fClipRestrictionSaveCount = -1; 1254cb93a386Sopenharmony_ci } 1255cb93a386Sopenharmony_ci // Update the quick-reject bounds in case the restore changed the top device or the 1256cb93a386Sopenharmony_ci // removed save record had included modifications to the clip stack. 1257cb93a386Sopenharmony_ci fQuickRejectBounds = this->computeDeviceClipBounds(); 1258cb93a386Sopenharmony_ci this->validateClip(); 1259cb93a386Sopenharmony_ci} 1260cb93a386Sopenharmony_ci 1261cb93a386Sopenharmony_cisk_sp<SkSurface> SkCanvas::makeSurface(const SkImageInfo& info, const SkSurfaceProps* props) { 1262cb93a386Sopenharmony_ci if (nullptr == props) { 1263cb93a386Sopenharmony_ci props = &fProps; 1264cb93a386Sopenharmony_ci } 1265cb93a386Sopenharmony_ci return this->onNewSurface(info, *props); 1266cb93a386Sopenharmony_ci} 1267cb93a386Sopenharmony_ci 1268cb93a386Sopenharmony_cisk_sp<SkSurface> SkCanvas::onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) { 1269cb93a386Sopenharmony_ci return this->baseDevice()->makeSurface(info, props); 1270cb93a386Sopenharmony_ci} 1271cb93a386Sopenharmony_ci 1272cb93a386Sopenharmony_ciSkImageInfo SkCanvas::imageInfo() const { 1273cb93a386Sopenharmony_ci return this->onImageInfo(); 1274cb93a386Sopenharmony_ci} 1275cb93a386Sopenharmony_ci 1276cb93a386Sopenharmony_ciSkImageInfo SkCanvas::onImageInfo() const { 1277cb93a386Sopenharmony_ci return this->baseDevice()->imageInfo(); 1278cb93a386Sopenharmony_ci} 1279cb93a386Sopenharmony_ci 1280cb93a386Sopenharmony_cibool SkCanvas::getProps(SkSurfaceProps* props) const { 1281cb93a386Sopenharmony_ci return this->onGetProps(props); 1282cb93a386Sopenharmony_ci} 1283cb93a386Sopenharmony_ci 1284cb93a386Sopenharmony_cibool SkCanvas::onGetProps(SkSurfaceProps* props) const { 1285cb93a386Sopenharmony_ci if (props) { 1286cb93a386Sopenharmony_ci *props = fProps; 1287cb93a386Sopenharmony_ci } 1288cb93a386Sopenharmony_ci return true; 1289cb93a386Sopenharmony_ci} 1290cb93a386Sopenharmony_ci 1291cb93a386Sopenharmony_cibool SkCanvas::peekPixels(SkPixmap* pmap) { 1292cb93a386Sopenharmony_ci return this->onPeekPixels(pmap); 1293cb93a386Sopenharmony_ci} 1294cb93a386Sopenharmony_ci 1295cb93a386Sopenharmony_cibool SkCanvas::onPeekPixels(SkPixmap* pmap) { 1296cb93a386Sopenharmony_ci return this->baseDevice()->peekPixels(pmap); 1297cb93a386Sopenharmony_ci} 1298cb93a386Sopenharmony_ci 1299cb93a386Sopenharmony_civoid* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin) { 1300cb93a386Sopenharmony_ci SkPixmap pmap; 1301cb93a386Sopenharmony_ci if (!this->onAccessTopLayerPixels(&pmap)) { 1302cb93a386Sopenharmony_ci return nullptr; 1303cb93a386Sopenharmony_ci } 1304cb93a386Sopenharmony_ci if (info) { 1305cb93a386Sopenharmony_ci *info = pmap.info(); 1306cb93a386Sopenharmony_ci } 1307cb93a386Sopenharmony_ci if (rowBytes) { 1308cb93a386Sopenharmony_ci *rowBytes = pmap.rowBytes(); 1309cb93a386Sopenharmony_ci } 1310cb93a386Sopenharmony_ci if (origin) { 1311cb93a386Sopenharmony_ci // If the caller requested the origin, they presumably are expecting the returned pixels to 1312cb93a386Sopenharmony_ci // be axis-aligned with the root canvas. If the top level device isn't axis aligned, that's 1313cb93a386Sopenharmony_ci // not the case. Until we update accessTopLayerPixels() to accept a coord space matrix 1314cb93a386Sopenharmony_ci // instead of an origin, just don't expose the pixels in that case. Note that this means 1315cb93a386Sopenharmony_ci // that layers with complex coordinate spaces can still report their pixels if the caller 1316cb93a386Sopenharmony_ci // does not ask for the origin (e.g. just to dump its output to a file, etc). 1317cb93a386Sopenharmony_ci if (this->topDevice()->isPixelAlignedToGlobal()) { 1318cb93a386Sopenharmony_ci *origin = this->topDevice()->getOrigin(); 1319cb93a386Sopenharmony_ci } else { 1320cb93a386Sopenharmony_ci return nullptr; 1321cb93a386Sopenharmony_ci } 1322cb93a386Sopenharmony_ci } 1323cb93a386Sopenharmony_ci return pmap.writable_addr(); 1324cb93a386Sopenharmony_ci} 1325cb93a386Sopenharmony_ci 1326cb93a386Sopenharmony_cibool SkCanvas::onAccessTopLayerPixels(SkPixmap* pmap) { 1327cb93a386Sopenharmony_ci return this->topDevice()->accessPixels(pmap); 1328cb93a386Sopenharmony_ci} 1329cb93a386Sopenharmony_ci 1330cb93a386Sopenharmony_ci///////////////////////////////////////////////////////////////////////////// 1331cb93a386Sopenharmony_ci 1332cb93a386Sopenharmony_civoid SkCanvas::translate(SkScalar dx, SkScalar dy) { 1333cb93a386Sopenharmony_ci if (dx || dy) { 1334cb93a386Sopenharmony_ci this->checkForDeferredSave(); 1335cb93a386Sopenharmony_ci fMCRec->fMatrix.preTranslate(dx, dy); 1336cb93a386Sopenharmony_ci 1337cb93a386Sopenharmony_ci this->topDevice()->setGlobalCTM(fMCRec->fMatrix); 1338cb93a386Sopenharmony_ci 1339cb93a386Sopenharmony_ci this->didTranslate(dx,dy); 1340cb93a386Sopenharmony_ci } 1341cb93a386Sopenharmony_ci} 1342cb93a386Sopenharmony_ci 1343cb93a386Sopenharmony_civoid SkCanvas::scale(SkScalar sx, SkScalar sy) { 1344cb93a386Sopenharmony_ci if (sx != 1 || sy != 1) { 1345cb93a386Sopenharmony_ci this->checkForDeferredSave(); 1346cb93a386Sopenharmony_ci fMCRec->fMatrix.preScale(sx, sy); 1347cb93a386Sopenharmony_ci 1348cb93a386Sopenharmony_ci this->topDevice()->setGlobalCTM(fMCRec->fMatrix); 1349cb93a386Sopenharmony_ci 1350cb93a386Sopenharmony_ci this->didScale(sx, sy); 1351cb93a386Sopenharmony_ci } 1352cb93a386Sopenharmony_ci} 1353cb93a386Sopenharmony_ci 1354cb93a386Sopenharmony_civoid SkCanvas::rotate(SkScalar degrees) { 1355cb93a386Sopenharmony_ci SkMatrix m; 1356cb93a386Sopenharmony_ci m.setRotate(degrees); 1357cb93a386Sopenharmony_ci this->concat(m); 1358cb93a386Sopenharmony_ci} 1359cb93a386Sopenharmony_ci 1360cb93a386Sopenharmony_civoid SkCanvas::rotate(SkScalar degrees, SkScalar px, SkScalar py) { 1361cb93a386Sopenharmony_ci SkMatrix m; 1362cb93a386Sopenharmony_ci m.setRotate(degrees, px, py); 1363cb93a386Sopenharmony_ci this->concat(m); 1364cb93a386Sopenharmony_ci} 1365cb93a386Sopenharmony_ci 1366cb93a386Sopenharmony_civoid SkCanvas::skew(SkScalar sx, SkScalar sy) { 1367cb93a386Sopenharmony_ci SkMatrix m; 1368cb93a386Sopenharmony_ci m.setSkew(sx, sy); 1369cb93a386Sopenharmony_ci this->concat(m); 1370cb93a386Sopenharmony_ci} 1371cb93a386Sopenharmony_ci 1372cb93a386Sopenharmony_civoid SkCanvas::concat(const SkMatrix& matrix) { 1373cb93a386Sopenharmony_ci if (matrix.isIdentity()) { 1374cb93a386Sopenharmony_ci return; 1375cb93a386Sopenharmony_ci } 1376cb93a386Sopenharmony_ci this->concat(SkM44(matrix)); 1377cb93a386Sopenharmony_ci} 1378cb93a386Sopenharmony_ci 1379cb93a386Sopenharmony_civoid SkCanvas::internalConcat44(const SkM44& m) { 1380cb93a386Sopenharmony_ci this->checkForDeferredSave(); 1381cb93a386Sopenharmony_ci 1382cb93a386Sopenharmony_ci fMCRec->fMatrix.preConcat(m); 1383cb93a386Sopenharmony_ci 1384cb93a386Sopenharmony_ci this->topDevice()->setGlobalCTM(fMCRec->fMatrix); 1385cb93a386Sopenharmony_ci} 1386cb93a386Sopenharmony_ci 1387cb93a386Sopenharmony_civoid SkCanvas::concat(const SkM44& m) { 1388cb93a386Sopenharmony_ci this->internalConcat44(m); 1389cb93a386Sopenharmony_ci // notify subclasses 1390cb93a386Sopenharmony_ci this->didConcat44(m); 1391cb93a386Sopenharmony_ci} 1392cb93a386Sopenharmony_ci 1393cb93a386Sopenharmony_civoid SkCanvas::internalSetMatrix(const SkM44& m) { 1394cb93a386Sopenharmony_ci fMCRec->fMatrix = m; 1395cb93a386Sopenharmony_ci 1396cb93a386Sopenharmony_ci this->topDevice()->setGlobalCTM(fMCRec->fMatrix); 1397cb93a386Sopenharmony_ci} 1398cb93a386Sopenharmony_ci 1399cb93a386Sopenharmony_civoid SkCanvas::setMatrix(const SkMatrix& matrix) { 1400cb93a386Sopenharmony_ci this->setMatrix(SkM44(matrix)); 1401cb93a386Sopenharmony_ci} 1402cb93a386Sopenharmony_ci 1403cb93a386Sopenharmony_civoid SkCanvas::setMatrix(const SkM44& m) { 1404cb93a386Sopenharmony_ci this->checkForDeferredSave(); 1405cb93a386Sopenharmony_ci this->internalSetMatrix(m); 1406cb93a386Sopenharmony_ci this->didSetM44(m); 1407cb93a386Sopenharmony_ci} 1408cb93a386Sopenharmony_ci 1409cb93a386Sopenharmony_civoid SkCanvas::resetMatrix() { 1410cb93a386Sopenharmony_ci this->setMatrix(SkM44()); 1411cb93a386Sopenharmony_ci} 1412cb93a386Sopenharmony_ci 1413cb93a386Sopenharmony_civoid SkCanvas::markCTM(const char* name) { 1414cb93a386Sopenharmony_ci if (SkCanvasPriv::ValidateMarker(name)) { 1415cb93a386Sopenharmony_ci fMarkerStack->setMarker(SkOpts::hash_fn(name, strlen(name), 0), 1416cb93a386Sopenharmony_ci this->getLocalToDevice(), fMCRec); 1417cb93a386Sopenharmony_ci this->onMarkCTM(name); 1418cb93a386Sopenharmony_ci } 1419cb93a386Sopenharmony_ci} 1420cb93a386Sopenharmony_ci 1421cb93a386Sopenharmony_cibool SkCanvas::findMarkedCTM(const char* name, SkM44* mx) const { 1422cb93a386Sopenharmony_ci return SkCanvasPriv::ValidateMarker(name) && 1423cb93a386Sopenharmony_ci fMarkerStack->findMarker(SkOpts::hash_fn(name, strlen(name), 0), mx); 1424cb93a386Sopenharmony_ci} 1425cb93a386Sopenharmony_ci 1426cb93a386Sopenharmony_ci////////////////////////////////////////////////////////////////////////////// 1427cb93a386Sopenharmony_ci 1428cb93a386Sopenharmony_civoid SkCanvas::clipRect(const SkRect& rect, SkClipOp op, bool doAA) { 1429cb93a386Sopenharmony_ci if (!rect.isFinite()) { 1430cb93a386Sopenharmony_ci return; 1431cb93a386Sopenharmony_ci } 1432cb93a386Sopenharmony_ci this->checkForDeferredSave(); 1433cb93a386Sopenharmony_ci ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle; 1434cb93a386Sopenharmony_ci this->onClipRect(rect.makeSorted(), op, edgeStyle); 1435cb93a386Sopenharmony_ci} 1436cb93a386Sopenharmony_ci 1437cb93a386Sopenharmony_civoid SkCanvas::onClipRect(const SkRect& rect, SkClipOp op, ClipEdgeStyle edgeStyle) { 1438cb93a386Sopenharmony_ci SkASSERT(rect.isSorted()); 1439cb93a386Sopenharmony_ci const bool isAA = kSoft_ClipEdgeStyle == edgeStyle; 1440cb93a386Sopenharmony_ci 1441cb93a386Sopenharmony_ci AutoUpdateQRBounds aqr(this); 1442cb93a386Sopenharmony_ci this->topDevice()->clipRect(rect, op, isAA); 1443cb93a386Sopenharmony_ci} 1444cb93a386Sopenharmony_ci 1445cb93a386Sopenharmony_civoid SkCanvas::androidFramework_setDeviceClipRestriction(const SkIRect& rect) { 1446cb93a386Sopenharmony_ci // The device clip restriction is a surface-space rectangular intersection that cannot be 1447cb93a386Sopenharmony_ci // drawn outside of. The rectangle is remembered so that subsequent resetClip calls still 1448cb93a386Sopenharmony_ci // respect the restriction. Other than clip resetting, all clip operations restrict the set 1449cb93a386Sopenharmony_ci // of renderable pixels, so once set, the restriction will be respected until the canvas 1450cb93a386Sopenharmony_ci // save stack is restored past the point this function was invoked. Unfortunately, the current 1451cb93a386Sopenharmony_ci // implementation relies on the clip stack of the underyling SkDevices, which leads to some 1452cb93a386Sopenharmony_ci // awkward behavioral interactions (see skbug.com/12252). 1453cb93a386Sopenharmony_ci // 1454cb93a386Sopenharmony_ci // Namely, a canvas restore() could undo the clip restriction's rect, and if 1455cb93a386Sopenharmony_ci // setDeviceClipRestriction were called at a nested save level, there's no way to undo just the 1456cb93a386Sopenharmony_ci // prior restriction and re-apply the new one. It also only makes sense to apply to the base 1457cb93a386Sopenharmony_ci // device; any other device for a saved layer will be clipped back to the base device during its 1458cb93a386Sopenharmony_ci // matched restore. As such, we: 1459cb93a386Sopenharmony_ci // - Remember the save count that added the clip restriction and reset the rect to empty when 1460cb93a386Sopenharmony_ci // we've restored past that point to keep our state in sync with the device's clip stack. 1461cb93a386Sopenharmony_ci // - We assert that we're on the base device when this is invoked. 1462cb93a386Sopenharmony_ci // - We assert that setDeviceClipRestriction() is only called when there was no prior 1463cb93a386Sopenharmony_ci // restriction (cannot re-restrict, and prior state must have been reset by restoring the 1464cb93a386Sopenharmony_ci // canvas state). 1465cb93a386Sopenharmony_ci // - Historically, the empty rect would reset the clip restriction but it only could do so 1466cb93a386Sopenharmony_ci // partially since the device's clips wasn't adjusted. Resetting is now handled 1467cb93a386Sopenharmony_ci // automatically via SkCanvas::restore(), so empty input rects are skipped. 1468cb93a386Sopenharmony_ci SkASSERT(this->topDevice() == this->baseDevice()); // shouldn't be in a nested layer 1469cb93a386Sopenharmony_ci // and shouldn't already have a restriction 1470cb93a386Sopenharmony_ci SkASSERT(fClipRestrictionSaveCount < 0 && fClipRestrictionRect.isEmpty()); 1471cb93a386Sopenharmony_ci 1472cb93a386Sopenharmony_ci if (fClipRestrictionSaveCount < 0 && !rect.isEmpty()) { 1473cb93a386Sopenharmony_ci fClipRestrictionRect = rect; 1474cb93a386Sopenharmony_ci fClipRestrictionSaveCount = this->getSaveCount(); 1475cb93a386Sopenharmony_ci 1476cb93a386Sopenharmony_ci // A non-empty clip restriction immediately applies an intersection op (ignoring the ctm). 1477cb93a386Sopenharmony_ci // so we have to resolve the save. 1478cb93a386Sopenharmony_ci this->checkForDeferredSave(); 1479cb93a386Sopenharmony_ci AutoUpdateQRBounds aqr(this); 1480cb93a386Sopenharmony_ci // Use clipRegion() since that operates in canvas-space, whereas clipRect() would apply the 1481cb93a386Sopenharmony_ci // device's current transform first. 1482cb93a386Sopenharmony_ci this->topDevice()->clipRegion(SkRegion(rect), SkClipOp::kIntersect); 1483cb93a386Sopenharmony_ci } 1484cb93a386Sopenharmony_ci} 1485cb93a386Sopenharmony_ci 1486cb93a386Sopenharmony_civoid SkCanvas::internal_private_resetClip() { 1487cb93a386Sopenharmony_ci this->checkForDeferredSave(); 1488cb93a386Sopenharmony_ci this->onResetClip(); 1489cb93a386Sopenharmony_ci} 1490cb93a386Sopenharmony_ci 1491cb93a386Sopenharmony_civoid SkCanvas::onResetClip() { 1492cb93a386Sopenharmony_ci SkIRect deviceRestriction = this->topDevice()->imageInfo().bounds(); 1493cb93a386Sopenharmony_ci if (fClipRestrictionSaveCount >= 0 && this->topDevice() == this->baseDevice()) { 1494cb93a386Sopenharmony_ci // Respect the device clip restriction when resetting the clip if we're on the base device. 1495cb93a386Sopenharmony_ci // If we're not on the base device, then the "reset" applies to the top device's clip stack, 1496cb93a386Sopenharmony_ci // and the clip restriction will be respected automatically during a restore of the layer. 1497cb93a386Sopenharmony_ci if (!deviceRestriction.intersect(fClipRestrictionRect)) { 1498cb93a386Sopenharmony_ci deviceRestriction = SkIRect::MakeEmpty(); 1499cb93a386Sopenharmony_ci } 1500cb93a386Sopenharmony_ci } 1501cb93a386Sopenharmony_ci 1502cb93a386Sopenharmony_ci AutoUpdateQRBounds aqr(this); 1503cb93a386Sopenharmony_ci this->topDevice()->replaceClip(deviceRestriction); 1504cb93a386Sopenharmony_ci} 1505cb93a386Sopenharmony_ci 1506cb93a386Sopenharmony_civoid SkCanvas::clipRRect(const SkRRect& rrect, SkClipOp op, bool doAA) { 1507cb93a386Sopenharmony_ci this->checkForDeferredSave(); 1508cb93a386Sopenharmony_ci ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle; 1509cb93a386Sopenharmony_ci if (rrect.isRect()) { 1510cb93a386Sopenharmony_ci this->onClipRect(rrect.getBounds(), op, edgeStyle); 1511cb93a386Sopenharmony_ci } else { 1512cb93a386Sopenharmony_ci this->onClipRRect(rrect, op, edgeStyle); 1513cb93a386Sopenharmony_ci } 1514cb93a386Sopenharmony_ci} 1515cb93a386Sopenharmony_ci 1516cb93a386Sopenharmony_civoid SkCanvas::onClipRRect(const SkRRect& rrect, SkClipOp op, ClipEdgeStyle edgeStyle) { 1517cb93a386Sopenharmony_ci bool isAA = kSoft_ClipEdgeStyle == edgeStyle; 1518cb93a386Sopenharmony_ci 1519cb93a386Sopenharmony_ci AutoUpdateQRBounds aqr(this); 1520cb93a386Sopenharmony_ci this->topDevice()->clipRRect(rrect, op, isAA); 1521cb93a386Sopenharmony_ci} 1522cb93a386Sopenharmony_ci 1523cb93a386Sopenharmony_civoid SkCanvas::clipPath(const SkPath& path, SkClipOp op, bool doAA) { 1524cb93a386Sopenharmony_ci this->checkForDeferredSave(); 1525cb93a386Sopenharmony_ci ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle; 1526cb93a386Sopenharmony_ci 1527cb93a386Sopenharmony_ci if (!path.isInverseFillType() && fMCRec->fMatrix.asM33().rectStaysRect()) { 1528cb93a386Sopenharmony_ci SkRect r; 1529cb93a386Sopenharmony_ci if (path.isRect(&r)) { 1530cb93a386Sopenharmony_ci this->onClipRect(r, op, edgeStyle); 1531cb93a386Sopenharmony_ci return; 1532cb93a386Sopenharmony_ci } 1533cb93a386Sopenharmony_ci SkRRect rrect; 1534cb93a386Sopenharmony_ci if (path.isOval(&r)) { 1535cb93a386Sopenharmony_ci rrect.setOval(r); 1536cb93a386Sopenharmony_ci this->onClipRRect(rrect, op, edgeStyle); 1537cb93a386Sopenharmony_ci return; 1538cb93a386Sopenharmony_ci } 1539cb93a386Sopenharmony_ci if (path.isRRect(&rrect)) { 1540cb93a386Sopenharmony_ci this->onClipRRect(rrect, op, edgeStyle); 1541cb93a386Sopenharmony_ci return; 1542cb93a386Sopenharmony_ci } 1543cb93a386Sopenharmony_ci } 1544cb93a386Sopenharmony_ci 1545cb93a386Sopenharmony_ci this->onClipPath(path, op, edgeStyle); 1546cb93a386Sopenharmony_ci} 1547cb93a386Sopenharmony_ci 1548cb93a386Sopenharmony_civoid SkCanvas::onClipPath(const SkPath& path, SkClipOp op, ClipEdgeStyle edgeStyle) { 1549cb93a386Sopenharmony_ci bool isAA = kSoft_ClipEdgeStyle == edgeStyle; 1550cb93a386Sopenharmony_ci 1551cb93a386Sopenharmony_ci AutoUpdateQRBounds aqr(this); 1552cb93a386Sopenharmony_ci this->topDevice()->clipPath(path, op, isAA); 1553cb93a386Sopenharmony_ci} 1554cb93a386Sopenharmony_ci 1555cb93a386Sopenharmony_civoid SkCanvas::clipShader(sk_sp<SkShader> sh, SkClipOp op) { 1556cb93a386Sopenharmony_ci if (sh) { 1557cb93a386Sopenharmony_ci if (sh->isOpaque()) { 1558cb93a386Sopenharmony_ci if (op == SkClipOp::kIntersect) { 1559cb93a386Sopenharmony_ci // we don't occlude anything, so skip this call 1560cb93a386Sopenharmony_ci } else { 1561cb93a386Sopenharmony_ci SkASSERT(op == SkClipOp::kDifference); 1562cb93a386Sopenharmony_ci // we occlude everything, so set the clip to empty 1563cb93a386Sopenharmony_ci this->clipRect({0,0,0,0}); 1564cb93a386Sopenharmony_ci } 1565cb93a386Sopenharmony_ci } else { 1566cb93a386Sopenharmony_ci this->checkForDeferredSave(); 1567cb93a386Sopenharmony_ci this->onClipShader(std::move(sh), op); 1568cb93a386Sopenharmony_ci } 1569cb93a386Sopenharmony_ci } 1570cb93a386Sopenharmony_ci} 1571cb93a386Sopenharmony_ci 1572cb93a386Sopenharmony_civoid SkCanvas::onClipShader(sk_sp<SkShader> sh, SkClipOp op) { 1573cb93a386Sopenharmony_ci AutoUpdateQRBounds aqr(this); 1574cb93a386Sopenharmony_ci this->topDevice()->clipShader(sh, op); 1575cb93a386Sopenharmony_ci} 1576cb93a386Sopenharmony_ci 1577cb93a386Sopenharmony_civoid SkCanvas::clipRegion(const SkRegion& rgn, SkClipOp op) { 1578cb93a386Sopenharmony_ci this->checkForDeferredSave(); 1579cb93a386Sopenharmony_ci this->onClipRegion(rgn, op); 1580cb93a386Sopenharmony_ci} 1581cb93a386Sopenharmony_ci 1582cb93a386Sopenharmony_civoid SkCanvas::onClipRegion(const SkRegion& rgn, SkClipOp op) { 1583cb93a386Sopenharmony_ci AutoUpdateQRBounds aqr(this); 1584cb93a386Sopenharmony_ci this->topDevice()->clipRegion(rgn, op); 1585cb93a386Sopenharmony_ci} 1586cb93a386Sopenharmony_ci 1587cb93a386Sopenharmony_civoid SkCanvas::validateClip() const { 1588cb93a386Sopenharmony_ci#ifdef SK_DEBUG 1589cb93a386Sopenharmony_ci SkRect tmp = this->computeDeviceClipBounds(); 1590cb93a386Sopenharmony_ci if (this->isClipEmpty()) { 1591cb93a386Sopenharmony_ci SkASSERT(fQuickRejectBounds.isEmpty()); 1592cb93a386Sopenharmony_ci } else { 1593cb93a386Sopenharmony_ci SkASSERT(tmp == fQuickRejectBounds); 1594cb93a386Sopenharmony_ci } 1595cb93a386Sopenharmony_ci#endif 1596cb93a386Sopenharmony_ci} 1597cb93a386Sopenharmony_ci 1598cb93a386Sopenharmony_cibool SkCanvas::androidFramework_isClipAA() const { 1599cb93a386Sopenharmony_ci return this->topDevice()->onClipIsAA(); 1600cb93a386Sopenharmony_ci} 1601cb93a386Sopenharmony_ci 1602cb93a386Sopenharmony_civoid SkCanvas::temporary_internal_getRgnClip(SkRegion* rgn) { 1603cb93a386Sopenharmony_ci rgn->setEmpty(); 1604cb93a386Sopenharmony_ci SkBaseDevice* device = this->topDevice(); 1605cb93a386Sopenharmony_ci if (device && device->isPixelAlignedToGlobal()) { 1606cb93a386Sopenharmony_ci device->onAsRgnClip(rgn); 1607cb93a386Sopenharmony_ci SkIPoint origin = device->getOrigin(); 1608cb93a386Sopenharmony_ci if (origin.x() | origin.y()) { 1609cb93a386Sopenharmony_ci rgn->translate(origin.x(), origin.y()); 1610cb93a386Sopenharmony_ci } 1611cb93a386Sopenharmony_ci } 1612cb93a386Sopenharmony_ci} 1613cb93a386Sopenharmony_ci 1614cb93a386Sopenharmony_ci/////////////////////////////////////////////////////////////////////////////// 1615cb93a386Sopenharmony_ci 1616cb93a386Sopenharmony_cibool SkCanvas::isClipEmpty() const { 1617cb93a386Sopenharmony_ci return this->topDevice()->onGetClipType() == SkBaseDevice::ClipType::kEmpty; 1618cb93a386Sopenharmony_ci} 1619cb93a386Sopenharmony_ci 1620cb93a386Sopenharmony_cibool SkCanvas::isClipRect() const { 1621cb93a386Sopenharmony_ci return this->topDevice()->onGetClipType() == SkBaseDevice::ClipType::kRect; 1622cb93a386Sopenharmony_ci} 1623cb93a386Sopenharmony_ci 1624cb93a386Sopenharmony_cibool SkCanvas::quickReject(const SkRect& src) const { 1625cb93a386Sopenharmony_ci#ifdef SK_DEBUG 1626cb93a386Sopenharmony_ci // Verify that fQuickRejectBounds are set properly. 1627cb93a386Sopenharmony_ci this->validateClip(); 1628cb93a386Sopenharmony_ci#endif 1629cb93a386Sopenharmony_ci 1630cb93a386Sopenharmony_ci SkRect devRect = SkMatrixPriv::MapRect(fMCRec->fMatrix, src); 1631cb93a386Sopenharmony_ci return !devRect.isFinite() || !devRect.intersects(fQuickRejectBounds); 1632cb93a386Sopenharmony_ci} 1633cb93a386Sopenharmony_ci 1634cb93a386Sopenharmony_cibool SkCanvas::quickReject(const SkPath& path) const { 1635cb93a386Sopenharmony_ci return path.isEmpty() || this->quickReject(path.getBounds()); 1636cb93a386Sopenharmony_ci} 1637cb93a386Sopenharmony_ci 1638cb93a386Sopenharmony_cibool SkCanvas::internalQuickReject(const SkRect& bounds, const SkPaint& paint, 1639cb93a386Sopenharmony_ci const SkMatrix* matrix) { 1640cb93a386Sopenharmony_ci if (!bounds.isFinite() || paint.nothingToDraw()) { 1641cb93a386Sopenharmony_ci return true; 1642cb93a386Sopenharmony_ci } 1643cb93a386Sopenharmony_ci 1644cb93a386Sopenharmony_ci if (paint.canComputeFastBounds()) { 1645cb93a386Sopenharmony_ci SkRect tmp = matrix ? matrix->mapRect(bounds) : bounds; 1646cb93a386Sopenharmony_ci return this->quickReject(paint.computeFastBounds(tmp, &tmp)); 1647cb93a386Sopenharmony_ci } 1648cb93a386Sopenharmony_ci 1649cb93a386Sopenharmony_ci return false; 1650cb93a386Sopenharmony_ci} 1651cb93a386Sopenharmony_ci 1652cb93a386Sopenharmony_ci 1653cb93a386Sopenharmony_ciSkRect SkCanvas::getLocalClipBounds() const { 1654cb93a386Sopenharmony_ci SkIRect ibounds = this->getDeviceClipBounds(); 1655cb93a386Sopenharmony_ci if (ibounds.isEmpty()) { 1656cb93a386Sopenharmony_ci return SkRect::MakeEmpty(); 1657cb93a386Sopenharmony_ci } 1658cb93a386Sopenharmony_ci 1659cb93a386Sopenharmony_ci SkMatrix inverse; 1660cb93a386Sopenharmony_ci // if we can't invert the CTM, we can't return local clip bounds 1661cb93a386Sopenharmony_ci if (!fMCRec->fMatrix.asM33().invert(&inverse)) { 1662cb93a386Sopenharmony_ci return SkRect::MakeEmpty(); 1663cb93a386Sopenharmony_ci } 1664cb93a386Sopenharmony_ci 1665cb93a386Sopenharmony_ci SkRect bounds; 1666cb93a386Sopenharmony_ci // adjust it outwards in case we are antialiasing 1667cb93a386Sopenharmony_ci const int margin = 1; 1668cb93a386Sopenharmony_ci 1669cb93a386Sopenharmony_ci SkRect r = SkRect::Make(ibounds.makeOutset(margin, margin)); 1670cb93a386Sopenharmony_ci inverse.mapRect(&bounds, r); 1671cb93a386Sopenharmony_ci return bounds; 1672cb93a386Sopenharmony_ci} 1673cb93a386Sopenharmony_ci 1674cb93a386Sopenharmony_ciSkIRect SkCanvas::getRoundInDeviceClipBounds() const { 1675cb93a386Sopenharmony_ci return this->computeDeviceClipBounds(/*outsetForAA=*/false).roundIn(); 1676cb93a386Sopenharmony_ci} 1677cb93a386Sopenharmony_ci 1678cb93a386Sopenharmony_ciSkIRect SkCanvas::getDeviceClipBounds() const { 1679cb93a386Sopenharmony_ci return this->computeDeviceClipBounds(/*outsetForAA=*/false).roundOut(); 1680cb93a386Sopenharmony_ci} 1681cb93a386Sopenharmony_ci 1682cb93a386Sopenharmony_ciSkRect SkCanvas::computeDeviceClipBounds(bool outsetForAA) const { 1683cb93a386Sopenharmony_ci const SkBaseDevice* dev = this->topDevice(); 1684cb93a386Sopenharmony_ci if (dev->onGetClipType() == SkBaseDevice::ClipType::kEmpty) { 1685cb93a386Sopenharmony_ci return SkRect::MakeEmpty(); 1686cb93a386Sopenharmony_ci } else { 1687cb93a386Sopenharmony_ci SkRect devClipBounds = 1688cb93a386Sopenharmony_ci SkMatrixPriv::MapRect(dev->deviceToGlobal(), SkRect::Make(dev->devClipBounds())); 1689cb93a386Sopenharmony_ci if (outsetForAA) { 1690cb93a386Sopenharmony_ci // Expand bounds out by 1 in case we are anti-aliasing. We store the 1691cb93a386Sopenharmony_ci // bounds as floats to enable a faster quick reject implementation. 1692cb93a386Sopenharmony_ci devClipBounds.outset(1.f, 1.f); 1693cb93a386Sopenharmony_ci } 1694cb93a386Sopenharmony_ci return devClipBounds; 1695cb93a386Sopenharmony_ci } 1696cb93a386Sopenharmony_ci} 1697cb93a386Sopenharmony_ci 1698cb93a386Sopenharmony_ci/////////////////////////////////////////////////////////////////////// 1699cb93a386Sopenharmony_ci 1700cb93a386Sopenharmony_ciSkMatrix SkCanvas::getTotalMatrix() const { 1701cb93a386Sopenharmony_ci return fMCRec->fMatrix.asM33(); 1702cb93a386Sopenharmony_ci} 1703cb93a386Sopenharmony_ci 1704cb93a386Sopenharmony_ciSkM44 SkCanvas::getLocalToDevice() const { 1705cb93a386Sopenharmony_ci return fMCRec->fMatrix; 1706cb93a386Sopenharmony_ci} 1707cb93a386Sopenharmony_ci 1708cb93a386Sopenharmony_ci#if defined(SK_BUILD_FOR_ANDROID_FRAMEWORK) && SK_SUPPORT_GPU 1709cb93a386Sopenharmony_ci 1710cb93a386Sopenharmony_ciSkIRect SkCanvas::topLayerBounds() const { 1711cb93a386Sopenharmony_ci return this->topDevice()->getGlobalBounds(); 1712cb93a386Sopenharmony_ci} 1713cb93a386Sopenharmony_ci 1714cb93a386Sopenharmony_ciGrBackendRenderTarget SkCanvas::topLayerBackendRenderTarget() const { 1715cb93a386Sopenharmony_ci auto proxy = SkCanvasPriv::TopDeviceTargetProxy(const_cast<SkCanvas*>(this)); 1716cb93a386Sopenharmony_ci if (!proxy) { 1717cb93a386Sopenharmony_ci return {}; 1718cb93a386Sopenharmony_ci } 1719cb93a386Sopenharmony_ci const GrRenderTarget* renderTarget = proxy->peekRenderTarget(); 1720cb93a386Sopenharmony_ci return renderTarget ? renderTarget->getBackendRenderTarget() : GrBackendRenderTarget(); 1721cb93a386Sopenharmony_ci} 1722cb93a386Sopenharmony_ci#endif 1723cb93a386Sopenharmony_ci 1724cb93a386Sopenharmony_ciGrRecordingContext* SkCanvas::recordingContext() { 1725cb93a386Sopenharmony_ci#if SK_SUPPORT_GPU 1726cb93a386Sopenharmony_ci if (auto gpuDevice = this->topDevice()->asGpuDevice()) { 1727cb93a386Sopenharmony_ci return gpuDevice->recordingContext(); 1728cb93a386Sopenharmony_ci } 1729cb93a386Sopenharmony_ci#endif 1730cb93a386Sopenharmony_ci 1731cb93a386Sopenharmony_ci return nullptr; 1732cb93a386Sopenharmony_ci} 1733cb93a386Sopenharmony_ci 1734cb93a386Sopenharmony_civoid SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner, 1735cb93a386Sopenharmony_ci const SkPaint& paint) { 1736cb93a386Sopenharmony_ci TRACE_EVENT0("skia", TRACE_FUNC); 1737cb93a386Sopenharmony_ci if (outer.isEmpty()) { 1738cb93a386Sopenharmony_ci return; 1739cb93a386Sopenharmony_ci } 1740cb93a386Sopenharmony_ci if (inner.isEmpty()) { 1741cb93a386Sopenharmony_ci this->drawRRect(outer, paint); 1742cb93a386Sopenharmony_ci return; 1743cb93a386Sopenharmony_ci } 1744cb93a386Sopenharmony_ci 1745cb93a386Sopenharmony_ci // We don't have this method (yet), but technically this is what we should 1746cb93a386Sopenharmony_ci // be able to return ... 1747cb93a386Sopenharmony_ci // if (!outer.contains(inner))) { 1748cb93a386Sopenharmony_ci // 1749cb93a386Sopenharmony_ci // For now at least check for containment of bounds 1750cb93a386Sopenharmony_ci if (!outer.getBounds().contains(inner.getBounds())) { 1751cb93a386Sopenharmony_ci return; 1752cb93a386Sopenharmony_ci } 1753cb93a386Sopenharmony_ci 1754cb93a386Sopenharmony_ci this->onDrawDRRect(outer, inner, paint); 1755cb93a386Sopenharmony_ci} 1756cb93a386Sopenharmony_ci 1757cb93a386Sopenharmony_civoid SkCanvas::drawPaint(const SkPaint& paint) { 1758cb93a386Sopenharmony_ci TRACE_EVENT0("skia", TRACE_FUNC); 1759cb93a386Sopenharmony_ci this->onDrawPaint(paint); 1760cb93a386Sopenharmony_ci} 1761cb93a386Sopenharmony_ci 1762cb93a386Sopenharmony_civoid SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) { 1763cb93a386Sopenharmony_ci TRACE_EVENT0("skia", TRACE_FUNC); 1764cb93a386Sopenharmony_ci // To avoid redundant logic in our culling code and various backends, we always sort rects 1765cb93a386Sopenharmony_ci // before passing them along. 1766cb93a386Sopenharmony_ci this->onDrawRect(r.makeSorted(), paint); 1767cb93a386Sopenharmony_ci} 1768cb93a386Sopenharmony_ci 1769cb93a386Sopenharmony_civoid SkCanvas::drawClippedToSaveBehind(const SkPaint& paint) { 1770cb93a386Sopenharmony_ci TRACE_EVENT0("skia", TRACE_FUNC); 1771cb93a386Sopenharmony_ci this->onDrawBehind(paint); 1772cb93a386Sopenharmony_ci} 1773cb93a386Sopenharmony_ci 1774cb93a386Sopenharmony_civoid SkCanvas::drawRegion(const SkRegion& region, const SkPaint& paint) { 1775cb93a386Sopenharmony_ci TRACE_EVENT0("skia", TRACE_FUNC); 1776cb93a386Sopenharmony_ci if (region.isEmpty()) { 1777cb93a386Sopenharmony_ci return; 1778cb93a386Sopenharmony_ci } 1779cb93a386Sopenharmony_ci 1780cb93a386Sopenharmony_ci if (region.isRect()) { 1781cb93a386Sopenharmony_ci return this->drawIRect(region.getBounds(), paint); 1782cb93a386Sopenharmony_ci } 1783cb93a386Sopenharmony_ci 1784cb93a386Sopenharmony_ci this->onDrawRegion(region, paint); 1785cb93a386Sopenharmony_ci} 1786cb93a386Sopenharmony_ci 1787cb93a386Sopenharmony_civoid SkCanvas::drawOval(const SkRect& r, const SkPaint& paint) { 1788cb93a386Sopenharmony_ci TRACE_EVENT0("skia", TRACE_FUNC); 1789cb93a386Sopenharmony_ci // To avoid redundant logic in our culling code and various backends, we always sort rects 1790cb93a386Sopenharmony_ci // before passing them along. 1791cb93a386Sopenharmony_ci this->onDrawOval(r.makeSorted(), paint); 1792cb93a386Sopenharmony_ci} 1793cb93a386Sopenharmony_ci 1794cb93a386Sopenharmony_civoid SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) { 1795cb93a386Sopenharmony_ci TRACE_EVENT0("skia", TRACE_FUNC); 1796cb93a386Sopenharmony_ci this->onDrawRRect(rrect, paint); 1797cb93a386Sopenharmony_ci} 1798cb93a386Sopenharmony_ci 1799cb93a386Sopenharmony_civoid SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) { 1800cb93a386Sopenharmony_ci TRACE_EVENT0("skia", TRACE_FUNC); 1801cb93a386Sopenharmony_ci this->onDrawPoints(mode, count, pts, paint); 1802cb93a386Sopenharmony_ci} 1803cb93a386Sopenharmony_ci 1804cb93a386Sopenharmony_civoid SkCanvas::drawVertices(const sk_sp<SkVertices>& vertices, SkBlendMode mode, 1805cb93a386Sopenharmony_ci const SkPaint& paint) { 1806cb93a386Sopenharmony_ci this->drawVertices(vertices.get(), mode, paint); 1807cb93a386Sopenharmony_ci} 1808cb93a386Sopenharmony_ci 1809cb93a386Sopenharmony_civoid SkCanvas::drawVertices(const SkVertices* vertices, SkBlendMode mode, const SkPaint& paint) { 1810cb93a386Sopenharmony_ci TRACE_EVENT0("skia", TRACE_FUNC); 1811cb93a386Sopenharmony_ci RETURN_ON_NULL(vertices); 1812cb93a386Sopenharmony_ci 1813cb93a386Sopenharmony_ci // We expect fans to be converted to triangles when building or deserializing SkVertices. 1814cb93a386Sopenharmony_ci SkASSERT(vertices->priv().mode() != SkVertices::kTriangleFan_VertexMode); 1815cb93a386Sopenharmony_ci 1816cb93a386Sopenharmony_ci#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK 1817cb93a386Sopenharmony_ci // Preserve legacy behavior for Android: ignore the SkShader if there are no texCoords present 1818cb93a386Sopenharmony_ci if (paint.getShader() && !vertices->priv().hasTexCoords()) { 1819cb93a386Sopenharmony_ci SkPaint noShaderPaint(paint); 1820cb93a386Sopenharmony_ci noShaderPaint.setShader(nullptr); 1821cb93a386Sopenharmony_ci this->onDrawVerticesObject(vertices, mode, noShaderPaint); 1822cb93a386Sopenharmony_ci return; 1823cb93a386Sopenharmony_ci } 1824cb93a386Sopenharmony_ci#endif 1825cb93a386Sopenharmony_ci 1826cb93a386Sopenharmony_ci this->onDrawVerticesObject(vertices, mode, paint); 1827cb93a386Sopenharmony_ci} 1828cb93a386Sopenharmony_ci 1829cb93a386Sopenharmony_civoid SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) { 1830cb93a386Sopenharmony_ci TRACE_EVENT0("skia", TRACE_FUNC); 1831cb93a386Sopenharmony_ci this->onDrawPath(path, paint); 1832cb93a386Sopenharmony_ci#ifdef SK_ENABLE_PATH_COMPLEXITY_DFX 1833cb93a386Sopenharmony_ci SkPathComplexityDfx::ShowPathComplexityDfx(this, path); 1834cb93a386Sopenharmony_ci#endif 1835cb93a386Sopenharmony_ci} 1836cb93a386Sopenharmony_ci 1837cb93a386Sopenharmony_ci// Returns true if the rect can be "filled" : non-empty and finite 1838cb93a386Sopenharmony_cistatic bool fillable(const SkRect& r) { 1839cb93a386Sopenharmony_ci SkScalar w = r.width(); 1840cb93a386Sopenharmony_ci SkScalar h = r.height(); 1841cb93a386Sopenharmony_ci return SkScalarIsFinite(w) && w > 0 && SkScalarIsFinite(h) && h > 0; 1842cb93a386Sopenharmony_ci} 1843cb93a386Sopenharmony_ci 1844cb93a386Sopenharmony_cistatic SkPaint clean_paint_for_lattice(const SkPaint* paint) { 1845cb93a386Sopenharmony_ci SkPaint cleaned; 1846cb93a386Sopenharmony_ci if (paint) { 1847cb93a386Sopenharmony_ci cleaned = *paint; 1848cb93a386Sopenharmony_ci cleaned.setMaskFilter(nullptr); 1849cb93a386Sopenharmony_ci cleaned.setAntiAlias(false); 1850cb93a386Sopenharmony_ci } 1851cb93a386Sopenharmony_ci return cleaned; 1852cb93a386Sopenharmony_ci} 1853cb93a386Sopenharmony_ci 1854cb93a386Sopenharmony_civoid SkCanvas::drawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst, 1855cb93a386Sopenharmony_ci SkFilterMode filter, const SkPaint* paint) { 1856cb93a386Sopenharmony_ci RETURN_ON_NULL(image); 1857cb93a386Sopenharmony_ci 1858cb93a386Sopenharmony_ci const int xdivs[] = {center.fLeft, center.fRight}; 1859cb93a386Sopenharmony_ci const int ydivs[] = {center.fTop, center.fBottom}; 1860cb93a386Sopenharmony_ci 1861cb93a386Sopenharmony_ci Lattice lat; 1862cb93a386Sopenharmony_ci lat.fXDivs = xdivs; 1863cb93a386Sopenharmony_ci lat.fYDivs = ydivs; 1864cb93a386Sopenharmony_ci lat.fRectTypes = nullptr; 1865cb93a386Sopenharmony_ci lat.fXCount = lat.fYCount = 2; 1866cb93a386Sopenharmony_ci lat.fBounds = nullptr; 1867cb93a386Sopenharmony_ci lat.fColors = nullptr; 1868cb93a386Sopenharmony_ci this->drawImageLattice(image, lat, dst, filter, paint); 1869cb93a386Sopenharmony_ci} 1870cb93a386Sopenharmony_ci 1871cb93a386Sopenharmony_civoid SkCanvas::drawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst, 1872cb93a386Sopenharmony_ci SkFilterMode filter, const SkPaint* paint) { 1873cb93a386Sopenharmony_ci TRACE_EVENT0("skia", TRACE_FUNC); 1874cb93a386Sopenharmony_ci RETURN_ON_NULL(image); 1875cb93a386Sopenharmony_ci if (dst.isEmpty()) { 1876cb93a386Sopenharmony_ci return; 1877cb93a386Sopenharmony_ci } 1878cb93a386Sopenharmony_ci 1879cb93a386Sopenharmony_ci SkIRect bounds; 1880cb93a386Sopenharmony_ci Lattice latticePlusBounds = lattice; 1881cb93a386Sopenharmony_ci if (!latticePlusBounds.fBounds) { 1882cb93a386Sopenharmony_ci bounds = SkIRect::MakeWH(image->width(), image->height()); 1883cb93a386Sopenharmony_ci latticePlusBounds.fBounds = &bounds; 1884cb93a386Sopenharmony_ci } 1885cb93a386Sopenharmony_ci 1886cb93a386Sopenharmony_ci if (SkLatticeIter::Valid(image->width(), image->height(), latticePlusBounds)) { 1887cb93a386Sopenharmony_ci SkPaint latticePaint = clean_paint_for_lattice(paint); 1888cb93a386Sopenharmony_ci this->onDrawImageLattice2(image, latticePlusBounds, dst, filter, &latticePaint); 1889cb93a386Sopenharmony_ci } else { 1890cb93a386Sopenharmony_ci this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()), dst, 1891cb93a386Sopenharmony_ci SkSamplingOptions(filter), paint, kStrict_SrcRectConstraint); 1892cb93a386Sopenharmony_ci } 1893cb93a386Sopenharmony_ci} 1894cb93a386Sopenharmony_ci 1895cb93a386Sopenharmony_civoid SkCanvas::drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[], 1896cb93a386Sopenharmony_ci const SkColor colors[], int count, SkBlendMode mode, 1897cb93a386Sopenharmony_ci const SkSamplingOptions& sampling, const SkRect* cull, 1898cb93a386Sopenharmony_ci const SkPaint* paint) { 1899cb93a386Sopenharmony_ci TRACE_EVENT0("skia", TRACE_FUNC); 1900cb93a386Sopenharmony_ci RETURN_ON_NULL(atlas); 1901cb93a386Sopenharmony_ci if (count <= 0) { 1902cb93a386Sopenharmony_ci return; 1903cb93a386Sopenharmony_ci } 1904cb93a386Sopenharmony_ci SkASSERT(atlas); 1905cb93a386Sopenharmony_ci SkASSERT(tex); 1906cb93a386Sopenharmony_ci this->onDrawAtlas2(atlas, xform, tex, colors, count, mode, sampling, cull, paint); 1907cb93a386Sopenharmony_ci} 1908cb93a386Sopenharmony_ci 1909cb93a386Sopenharmony_civoid SkCanvas::drawAnnotation(const SkRect& rect, const char key[], SkData* value) { 1910cb93a386Sopenharmony_ci TRACE_EVENT0("skia", TRACE_FUNC); 1911cb93a386Sopenharmony_ci if (key) { 1912cb93a386Sopenharmony_ci this->onDrawAnnotation(rect, key, value); 1913cb93a386Sopenharmony_ci } 1914cb93a386Sopenharmony_ci} 1915cb93a386Sopenharmony_ci 1916cb93a386Sopenharmony_civoid SkCanvas::private_draw_shadow_rec(const SkPath& path, const SkDrawShadowRec& rec) { 1917cb93a386Sopenharmony_ci TRACE_EVENT0("skia", TRACE_FUNC); 1918cb93a386Sopenharmony_ci this->onDrawShadowRec(path, rec); 1919cb93a386Sopenharmony_ci} 1920cb93a386Sopenharmony_ci 1921cb93a386Sopenharmony_civoid SkCanvas::onDrawShadowRec(const SkPath& path, const SkDrawShadowRec& rec) { 1922cb93a386Sopenharmony_ci // We don't test quickReject because the shadow outsets the path's bounds. 1923cb93a386Sopenharmony_ci // TODO(michaelludwig): Is it worth calling SkDrawShadowMetrics::GetLocalBounds here? 1924cb93a386Sopenharmony_ci if (!this->predrawNotify()) { 1925cb93a386Sopenharmony_ci return; 1926cb93a386Sopenharmony_ci } 1927cb93a386Sopenharmony_ci this->topDevice()->drawShadow(path, rec); 1928cb93a386Sopenharmony_ci} 1929cb93a386Sopenharmony_ci 1930cb93a386Sopenharmony_civoid SkCanvas::experimental_DrawEdgeAAQuad(const SkRect& rect, const SkPoint clip[4], 1931cb93a386Sopenharmony_ci QuadAAFlags aaFlags, const SkColor4f& color, 1932cb93a386Sopenharmony_ci SkBlendMode mode) { 1933cb93a386Sopenharmony_ci TRACE_EVENT0("skia", TRACE_FUNC); 1934cb93a386Sopenharmony_ci // Make sure the rect is sorted before passing it along 1935cb93a386Sopenharmony_ci this->onDrawEdgeAAQuad(rect.makeSorted(), clip, aaFlags, color, mode); 1936cb93a386Sopenharmony_ci} 1937cb93a386Sopenharmony_ci 1938cb93a386Sopenharmony_civoid SkCanvas::experimental_DrawEdgeAAImageSet(const ImageSetEntry imageSet[], int cnt, 1939cb93a386Sopenharmony_ci const SkPoint dstClips[], 1940cb93a386Sopenharmony_ci const SkMatrix preViewMatrices[], 1941cb93a386Sopenharmony_ci const SkSamplingOptions& sampling, 1942cb93a386Sopenharmony_ci const SkPaint* paint, 1943cb93a386Sopenharmony_ci SrcRectConstraint constraint) { 1944cb93a386Sopenharmony_ci TRACE_EVENT0("skia", TRACE_FUNC); 1945cb93a386Sopenharmony_ci this->onDrawEdgeAAImageSet2(imageSet, cnt, dstClips, preViewMatrices, sampling, paint, 1946cb93a386Sopenharmony_ci constraint); 1947cb93a386Sopenharmony_ci} 1948cb93a386Sopenharmony_ci 1949cb93a386Sopenharmony_ci////////////////////////////////////////////////////////////////////////////// 1950cb93a386Sopenharmony_ci// These are the virtual drawing methods 1951cb93a386Sopenharmony_ci////////////////////////////////////////////////////////////////////////////// 1952cb93a386Sopenharmony_ci 1953cb93a386Sopenharmony_civoid SkCanvas::onDiscard() { 1954cb93a386Sopenharmony_ci if (fSurfaceBase) { 1955cb93a386Sopenharmony_ci sk_ignore_unused_variable(fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode)); 1956cb93a386Sopenharmony_ci } 1957cb93a386Sopenharmony_ci} 1958cb93a386Sopenharmony_ci 1959cb93a386Sopenharmony_civoid SkCanvas::onDrawPaint(const SkPaint& paint) { 1960cb93a386Sopenharmony_ci this->internalDrawPaint(paint); 1961cb93a386Sopenharmony_ci} 1962cb93a386Sopenharmony_ci 1963cb93a386Sopenharmony_civoid SkCanvas::internalDrawPaint(const SkPaint& paint) { 1964cb93a386Sopenharmony_ci // drawPaint does not call internalQuickReject() because computing its geometry is not free 1965cb93a386Sopenharmony_ci // (see getLocalClipBounds(), and the two conditions below are sufficient. 1966cb93a386Sopenharmony_ci if (paint.nothingToDraw() || this->isClipEmpty()) { 1967cb93a386Sopenharmony_ci return; 1968cb93a386Sopenharmony_ci } 1969cb93a386Sopenharmony_ci 1970cb93a386Sopenharmony_ci auto layer = this->aboutToDraw(this, paint, nullptr, CheckForOverwrite::kYes); 1971cb93a386Sopenharmony_ci if (layer) { 1972cb93a386Sopenharmony_ci this->topDevice()->drawPaint(layer->paint()); 1973cb93a386Sopenharmony_ci } 1974cb93a386Sopenharmony_ci} 1975cb93a386Sopenharmony_ci 1976cb93a386Sopenharmony_civoid SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[], 1977cb93a386Sopenharmony_ci const SkPaint& paint) { 1978cb93a386Sopenharmony_ci if ((long)count <= 0 || paint.nothingToDraw()) { 1979cb93a386Sopenharmony_ci return; 1980cb93a386Sopenharmony_ci } 1981cb93a386Sopenharmony_ci SkASSERT(pts != nullptr); 1982cb93a386Sopenharmony_ci 1983cb93a386Sopenharmony_ci SkRect bounds; 1984cb93a386Sopenharmony_ci // Compute bounds from points (common for drawing a single line) 1985cb93a386Sopenharmony_ci if (count == 2) { 1986cb93a386Sopenharmony_ci bounds.set(pts[0], pts[1]); 1987cb93a386Sopenharmony_ci } else { 1988cb93a386Sopenharmony_ci bounds.setBounds(pts, SkToInt(count)); 1989cb93a386Sopenharmony_ci } 1990cb93a386Sopenharmony_ci 1991cb93a386Sopenharmony_ci // Enforce paint style matches implicit behavior of drawPoints 1992cb93a386Sopenharmony_ci SkPaint strokePaint = paint; 1993cb93a386Sopenharmony_ci strokePaint.setStyle(SkPaint::kStroke_Style); 1994cb93a386Sopenharmony_ci if (this->internalQuickReject(bounds, strokePaint)) { 1995cb93a386Sopenharmony_ci return; 1996cb93a386Sopenharmony_ci } 1997cb93a386Sopenharmony_ci 1998cb93a386Sopenharmony_ci auto layer = this->aboutToDraw(this, strokePaint, &bounds); 1999cb93a386Sopenharmony_ci if (layer) { 2000cb93a386Sopenharmony_ci this->topDevice()->drawPoints(mode, count, pts, layer->paint()); 2001cb93a386Sopenharmony_ci } 2002cb93a386Sopenharmony_ci} 2003cb93a386Sopenharmony_ci 2004cb93a386Sopenharmony_civoid SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) { 2005cb93a386Sopenharmony_ci SkASSERT(r.isSorted()); 2006cb93a386Sopenharmony_ci if (this->internalQuickReject(r, paint)) { 2007cb93a386Sopenharmony_ci return; 2008cb93a386Sopenharmony_ci } 2009cb93a386Sopenharmony_ci 2010cb93a386Sopenharmony_ci auto layer = this->aboutToDraw(this, paint, &r, CheckForOverwrite::kYes); 2011cb93a386Sopenharmony_ci if (layer) { 2012cb93a386Sopenharmony_ci this->topDevice()->drawRect(r, layer->paint()); 2013cb93a386Sopenharmony_ci } 2014cb93a386Sopenharmony_ci} 2015cb93a386Sopenharmony_ci 2016cb93a386Sopenharmony_civoid SkCanvas::onDrawRegion(const SkRegion& region, const SkPaint& paint) { 2017cb93a386Sopenharmony_ci const SkRect bounds = SkRect::Make(region.getBounds()); 2018cb93a386Sopenharmony_ci if (this->internalQuickReject(bounds, paint)) { 2019cb93a386Sopenharmony_ci return; 2020cb93a386Sopenharmony_ci } 2021cb93a386Sopenharmony_ci 2022cb93a386Sopenharmony_ci auto layer = this->aboutToDraw(this, paint, &bounds); 2023cb93a386Sopenharmony_ci if (layer) { 2024cb93a386Sopenharmony_ci this->topDevice()->drawRegion(region, layer->paint()); 2025cb93a386Sopenharmony_ci } 2026cb93a386Sopenharmony_ci} 2027cb93a386Sopenharmony_ci 2028cb93a386Sopenharmony_civoid SkCanvas::onDrawBehind(const SkPaint& paint) { 2029cb93a386Sopenharmony_ci SkBaseDevice* dev = this->topDevice(); 2030cb93a386Sopenharmony_ci if (!dev) { 2031cb93a386Sopenharmony_ci return; 2032cb93a386Sopenharmony_ci } 2033cb93a386Sopenharmony_ci 2034cb93a386Sopenharmony_ci SkIRect bounds; 2035cb93a386Sopenharmony_ci SkDeque::Iter iter(fMCStack, SkDeque::Iter::kBack_IterStart); 2036cb93a386Sopenharmony_ci for (;;) { 2037cb93a386Sopenharmony_ci const MCRec* rec = (const MCRec*)iter.prev(); 2038cb93a386Sopenharmony_ci if (!rec) { 2039cb93a386Sopenharmony_ci return; // no backimages, so nothing to draw 2040cb93a386Sopenharmony_ci } 2041cb93a386Sopenharmony_ci if (rec->fBackImage) { 2042cb93a386Sopenharmony_ci // drawBehind should only have been called when the saveBehind record is active; 2043cb93a386Sopenharmony_ci // if this fails, it means a real saveLayer was made w/o being restored first. 2044cb93a386Sopenharmony_ci SkASSERT(dev == rec->fDevice); 2045cb93a386Sopenharmony_ci bounds = SkIRect::MakeXYWH(rec->fBackImage->fLoc.fX, rec->fBackImage->fLoc.fY, 2046cb93a386Sopenharmony_ci rec->fBackImage->fImage->width(), 2047cb93a386Sopenharmony_ci rec->fBackImage->fImage->height()); 2048cb93a386Sopenharmony_ci break; 2049cb93a386Sopenharmony_ci } 2050cb93a386Sopenharmony_ci } 2051cb93a386Sopenharmony_ci 2052cb93a386Sopenharmony_ci // The backimage location (and thus bounds) were defined in the device's space, so mark it 2053cb93a386Sopenharmony_ci // as a clip. We use a clip instead of just drawing a rect in case the paint has an image 2054cb93a386Sopenharmony_ci // filter on it (which is applied before any auto-layer so the filter is clipped). 2055cb93a386Sopenharmony_ci dev->save(); 2056cb93a386Sopenharmony_ci { 2057cb93a386Sopenharmony_ci // We also have to temporarily whack the device matrix since clipRegion is affected by the 2058cb93a386Sopenharmony_ci // global-to-device matrix and clipRect is affected by the local-to-device. 2059cb93a386Sopenharmony_ci SkAutoDeviceTransformRestore adtr(dev, SkMatrix::I()); 2060cb93a386Sopenharmony_ci dev->clipRect(SkRect::Make(bounds), SkClipOp::kIntersect, /* aa */ false); 2061cb93a386Sopenharmony_ci // ~adtr will reset the local-to-device matrix so that drawPaint() shades correctly. 2062cb93a386Sopenharmony_ci } 2063cb93a386Sopenharmony_ci 2064cb93a386Sopenharmony_ci auto layer = this->aboutToDraw(this, paint); 2065cb93a386Sopenharmony_ci if (layer) { 2066cb93a386Sopenharmony_ci this->topDevice()->drawPaint(layer->paint()); 2067cb93a386Sopenharmony_ci } 2068cb93a386Sopenharmony_ci 2069cb93a386Sopenharmony_ci dev->restore(fMCRec->fMatrix); 2070cb93a386Sopenharmony_ci} 2071cb93a386Sopenharmony_ci 2072cb93a386Sopenharmony_civoid SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) { 2073cb93a386Sopenharmony_ci SkASSERT(oval.isSorted()); 2074cb93a386Sopenharmony_ci if (this->internalQuickReject(oval, paint)) { 2075cb93a386Sopenharmony_ci return; 2076cb93a386Sopenharmony_ci } 2077cb93a386Sopenharmony_ci 2078cb93a386Sopenharmony_ci auto layer = this->aboutToDraw(this, paint, &oval); 2079cb93a386Sopenharmony_ci if (layer) { 2080cb93a386Sopenharmony_ci this->topDevice()->drawOval(oval, layer->paint()); 2081cb93a386Sopenharmony_ci } 2082cb93a386Sopenharmony_ci} 2083cb93a386Sopenharmony_ci 2084cb93a386Sopenharmony_civoid SkCanvas::onDrawArc(const SkRect& oval, SkScalar startAngle, 2085cb93a386Sopenharmony_ci SkScalar sweepAngle, bool useCenter, 2086cb93a386Sopenharmony_ci const SkPaint& paint) { 2087cb93a386Sopenharmony_ci SkASSERT(oval.isSorted()); 2088cb93a386Sopenharmony_ci if (this->internalQuickReject(oval, paint)) { 2089cb93a386Sopenharmony_ci return; 2090cb93a386Sopenharmony_ci } 2091cb93a386Sopenharmony_ci 2092cb93a386Sopenharmony_ci auto layer = this->aboutToDraw(this, paint, &oval); 2093cb93a386Sopenharmony_ci if (layer) { 2094cb93a386Sopenharmony_ci this->topDevice()->drawArc(oval, startAngle, sweepAngle, useCenter, layer->paint()); 2095cb93a386Sopenharmony_ci } 2096cb93a386Sopenharmony_ci} 2097cb93a386Sopenharmony_ci 2098cb93a386Sopenharmony_civoid SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) { 2099cb93a386Sopenharmony_ci const SkRect& bounds = rrect.getBounds(); 2100cb93a386Sopenharmony_ci 2101cb93a386Sopenharmony_ci // Delegating to simpler draw operations 2102cb93a386Sopenharmony_ci if (rrect.isRect()) { 2103cb93a386Sopenharmony_ci // call the non-virtual version 2104cb93a386Sopenharmony_ci this->SkCanvas::drawRect(bounds, paint); 2105cb93a386Sopenharmony_ci return; 2106cb93a386Sopenharmony_ci } else if (rrect.isOval()) { 2107cb93a386Sopenharmony_ci // call the non-virtual version 2108cb93a386Sopenharmony_ci this->SkCanvas::drawOval(bounds, paint); 2109cb93a386Sopenharmony_ci return; 2110cb93a386Sopenharmony_ci } 2111cb93a386Sopenharmony_ci 2112cb93a386Sopenharmony_ci if (this->internalQuickReject(bounds, paint)) { 2113cb93a386Sopenharmony_ci return; 2114cb93a386Sopenharmony_ci } 2115cb93a386Sopenharmony_ci 2116cb93a386Sopenharmony_ci auto layer = this->aboutToDraw(this, paint, &bounds); 2117cb93a386Sopenharmony_ci if (layer) { 2118cb93a386Sopenharmony_ci this->topDevice()->drawRRect(rrect, layer->paint()); 2119cb93a386Sopenharmony_ci } 2120cb93a386Sopenharmony_ci} 2121cb93a386Sopenharmony_ci 2122cb93a386Sopenharmony_civoid SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint) { 2123cb93a386Sopenharmony_ci const SkRect& bounds = outer.getBounds(); 2124cb93a386Sopenharmony_ci if (this->internalQuickReject(bounds, paint)) { 2125cb93a386Sopenharmony_ci return; 2126cb93a386Sopenharmony_ci } 2127cb93a386Sopenharmony_ci 2128cb93a386Sopenharmony_ci auto layer = this->aboutToDraw(this, paint, &bounds); 2129cb93a386Sopenharmony_ci if (layer) { 2130cb93a386Sopenharmony_ci this->topDevice()->drawDRRect(outer, inner, layer->paint()); 2131cb93a386Sopenharmony_ci } 2132cb93a386Sopenharmony_ci} 2133cb93a386Sopenharmony_ci 2134cb93a386Sopenharmony_civoid SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) { 2135cb93a386Sopenharmony_ci if (!path.isFinite()) { 2136cb93a386Sopenharmony_ci return; 2137cb93a386Sopenharmony_ci } 2138cb93a386Sopenharmony_ci 2139cb93a386Sopenharmony_ci const SkRect& pathBounds = path.getBounds(); 2140cb93a386Sopenharmony_ci if (!path.isInverseFillType() && this->internalQuickReject(pathBounds, paint)) { 2141cb93a386Sopenharmony_ci return; 2142cb93a386Sopenharmony_ci } 2143cb93a386Sopenharmony_ci if (path.isInverseFillType() && pathBounds.width() <= 0 && pathBounds.height() <= 0) { 2144cb93a386Sopenharmony_ci this->internalDrawPaint(paint); 2145cb93a386Sopenharmony_ci return; 2146cb93a386Sopenharmony_ci } 2147cb93a386Sopenharmony_ci 2148cb93a386Sopenharmony_ci auto layer = this->aboutToDraw(this, paint, &pathBounds); 2149cb93a386Sopenharmony_ci if (layer) { 2150cb93a386Sopenharmony_ci this->topDevice()->drawPath(path, layer->paint()); 2151cb93a386Sopenharmony_ci } 2152cb93a386Sopenharmony_ci} 2153cb93a386Sopenharmony_ci 2154cb93a386Sopenharmony_cibool SkCanvas::canDrawBitmapAsSprite(SkScalar x, SkScalar y, int w, int h, 2155cb93a386Sopenharmony_ci const SkSamplingOptions& sampling, const SkPaint& paint) { 2156cb93a386Sopenharmony_ci if (!paint.getImageFilter()) { 2157cb93a386Sopenharmony_ci return false; 2158cb93a386Sopenharmony_ci } 2159cb93a386Sopenharmony_ci 2160cb93a386Sopenharmony_ci const SkMatrix& ctm = this->getTotalMatrix(); 2161cb93a386Sopenharmony_ci if (!SkTreatAsSprite(ctm, SkISize::Make(w, h), sampling, paint)) { 2162cb93a386Sopenharmony_ci return false; 2163cb93a386Sopenharmony_ci } 2164cb93a386Sopenharmony_ci 2165cb93a386Sopenharmony_ci // The other paint effects need to be applied before the image filter, but the sprite draw 2166cb93a386Sopenharmony_ci // applies the filter explicitly first. 2167cb93a386Sopenharmony_ci if (paint.getAlphaf() < 1.f || paint.getColorFilter() || paint.getMaskFilter()) { 2168cb93a386Sopenharmony_ci return false; 2169cb93a386Sopenharmony_ci } 2170cb93a386Sopenharmony_ci // Currently we can only use the filterSprite code if we are clipped to the bitmap's bounds. 2171cb93a386Sopenharmony_ci // Once we can filter and the filter will return a result larger than itself, we should be 2172cb93a386Sopenharmony_ci // able to remove this constraint. 2173cb93a386Sopenharmony_ci // skbug.com/4526 2174cb93a386Sopenharmony_ci // 2175cb93a386Sopenharmony_ci SkPoint pt; 2176cb93a386Sopenharmony_ci ctm.mapXY(x, y, &pt); 2177cb93a386Sopenharmony_ci SkIRect ir = SkIRect::MakeXYWH(SkScalarRoundToInt(pt.x()), SkScalarRoundToInt(pt.y()), w, h); 2178cb93a386Sopenharmony_ci // quick bounds have been outset by 1px compared to overall device bounds, so this makes the 2179cb93a386Sopenharmony_ci // contains check equivalent to between ir and device bounds 2180cb93a386Sopenharmony_ci ir.outset(1, 1); 2181cb93a386Sopenharmony_ci return ir.contains(fQuickRejectBounds); 2182cb93a386Sopenharmony_ci} 2183cb93a386Sopenharmony_ci 2184cb93a386Sopenharmony_ci// Clean-up the paint to match the drawing semantics for drawImage et al. (skbug.com/7804). 2185cb93a386Sopenharmony_cistatic SkPaint clean_paint_for_drawImage(const SkPaint* paint) { 2186cb93a386Sopenharmony_ci SkPaint cleaned; 2187cb93a386Sopenharmony_ci if (paint) { 2188cb93a386Sopenharmony_ci cleaned = *paint; 2189cb93a386Sopenharmony_ci cleaned.setStyle(SkPaint::kFill_Style); 2190cb93a386Sopenharmony_ci cleaned.setPathEffect(nullptr); 2191cb93a386Sopenharmony_ci } 2192cb93a386Sopenharmony_ci return cleaned; 2193cb93a386Sopenharmony_ci} 2194cb93a386Sopenharmony_ci 2195cb93a386Sopenharmony_ci// drawVertices fills triangles and ignores mask filter and path effect, 2196cb93a386Sopenharmony_ci// so canonicalize the paint before checking quick reject. 2197cb93a386Sopenharmony_cistatic SkPaint clean_paint_for_drawVertices(SkPaint paint) { 2198cb93a386Sopenharmony_ci paint.setStyle(SkPaint::kFill_Style); 2199cb93a386Sopenharmony_ci paint.setMaskFilter(nullptr); 2200cb93a386Sopenharmony_ci paint.setPathEffect(nullptr); 2201cb93a386Sopenharmony_ci return paint; 2202cb93a386Sopenharmony_ci} 2203cb93a386Sopenharmony_ci 2204cb93a386Sopenharmony_civoid SkCanvas::onDrawImage2(const SkImage* image, SkScalar x, SkScalar y, 2205cb93a386Sopenharmony_ci const SkSamplingOptions& sampling, const SkPaint* paint) { 2206cb93a386Sopenharmony_ci SkPaint realPaint = clean_paint_for_drawImage(paint); 2207cb93a386Sopenharmony_ci 2208cb93a386Sopenharmony_ci SkRect bounds = SkRect::MakeXYWH(x, y, image->width(), image->height()); 2209cb93a386Sopenharmony_ci if (this->internalQuickReject(bounds, realPaint)) { 2210cb93a386Sopenharmony_ci return; 2211cb93a386Sopenharmony_ci } 2212cb93a386Sopenharmony_ci 2213cb93a386Sopenharmony_ci if (realPaint.getImageFilter() && 2214cb93a386Sopenharmony_ci this->canDrawBitmapAsSprite(x, y, image->width(), image->height(), sampling, realPaint) && 2215cb93a386Sopenharmony_ci !image_to_color_filter(&realPaint)) { 2216cb93a386Sopenharmony_ci // Evaluate the image filter directly on the input image and then draw the result, instead 2217cb93a386Sopenharmony_ci // of first drawing the image to a temporary layer and filtering. 2218cb93a386Sopenharmony_ci SkBaseDevice* device = this->topDevice(); 2219cb93a386Sopenharmony_ci sk_sp<SkSpecialImage> special; 2220cb93a386Sopenharmony_ci if ((special = device->makeSpecial(image))) { 2221cb93a386Sopenharmony_ci sk_sp<SkImageFilter> filter = realPaint.refImageFilter(); 2222cb93a386Sopenharmony_ci realPaint.setImageFilter(nullptr); 2223cb93a386Sopenharmony_ci 2224cb93a386Sopenharmony_ci // TODO(michaelludwig) - Many filters could probably be evaluated like this even if the 2225cb93a386Sopenharmony_ci // CTM is not translate-only; the post-transformation of the filtered image by the CTM 2226cb93a386Sopenharmony_ci // will probably look just as good and not require an extra layer. 2227cb93a386Sopenharmony_ci // TODO(michaelludwig) - Once image filter implementations can support source images 2228cb93a386Sopenharmony_ci // with non-(0,0) origins, we can just mark the origin as (x,y) instead of doing a 2229cb93a386Sopenharmony_ci // pre-concat here. 2230cb93a386Sopenharmony_ci SkMatrix layerToDevice = device->localToDevice(); 2231cb93a386Sopenharmony_ci layerToDevice.preTranslate(x, y); 2232cb93a386Sopenharmony_ci skif::Mapping mapping(layerToDevice, SkMatrix::Translate(-x, -y)); 2233cb93a386Sopenharmony_ci 2234cb93a386Sopenharmony_ci if (this->predrawNotify()) { 2235cb93a386Sopenharmony_ci device->drawFilteredImage(mapping, special.get(), filter.get(), sampling,realPaint); 2236cb93a386Sopenharmony_ci } 2237cb93a386Sopenharmony_ci return; 2238cb93a386Sopenharmony_ci } // else fall through to regular drawing path 2239cb93a386Sopenharmony_ci } 2240cb93a386Sopenharmony_ci 2241cb93a386Sopenharmony_ci auto layer = this->aboutToDraw(this, realPaint, &bounds); 2242cb93a386Sopenharmony_ci if (layer) { 2243cb93a386Sopenharmony_ci this->topDevice()->drawImageRect(image, nullptr, bounds, sampling, 2244cb93a386Sopenharmony_ci layer->paint(), kStrict_SrcRectConstraint); 2245cb93a386Sopenharmony_ci } 2246cb93a386Sopenharmony_ci} 2247cb93a386Sopenharmony_ci 2248cb93a386Sopenharmony_civoid SkCanvas::onDrawImageRect2(const SkImage* image, const SkRect& src, const SkRect& dst, 2249cb93a386Sopenharmony_ci const SkSamplingOptions& sampling, const SkPaint* paint, 2250cb93a386Sopenharmony_ci SrcRectConstraint constraint) { 2251cb93a386Sopenharmony_ci SkPaint realPaint = clean_paint_for_drawImage(paint); 2252cb93a386Sopenharmony_ci 2253cb93a386Sopenharmony_ci if (this->internalQuickReject(dst, realPaint)) { 2254cb93a386Sopenharmony_ci return; 2255cb93a386Sopenharmony_ci } 2256cb93a386Sopenharmony_ci 2257cb93a386Sopenharmony_ci auto layer = this->aboutToDraw(this, realPaint, &dst, CheckForOverwrite::kYes, 2258cb93a386Sopenharmony_ci image->isOpaque() ? kOpaque_ShaderOverrideOpacity 2259cb93a386Sopenharmony_ci : kNotOpaque_ShaderOverrideOpacity); 2260cb93a386Sopenharmony_ci if (layer) { 2261cb93a386Sopenharmony_ci this->topDevice()->drawImageRect(image, &src, dst, sampling, layer->paint(), constraint); 2262cb93a386Sopenharmony_ci } 2263cb93a386Sopenharmony_ci} 2264cb93a386Sopenharmony_ci 2265cb93a386Sopenharmony_civoid SkCanvas::onDrawImageLattice2(const SkImage* image, const Lattice& lattice, const SkRect& dst, 2266cb93a386Sopenharmony_ci SkFilterMode filter, const SkPaint* paint) { 2267cb93a386Sopenharmony_ci SkPaint realPaint = clean_paint_for_drawImage(paint); 2268cb93a386Sopenharmony_ci 2269cb93a386Sopenharmony_ci if (this->internalQuickReject(dst, realPaint)) { 2270cb93a386Sopenharmony_ci return; 2271cb93a386Sopenharmony_ci } 2272cb93a386Sopenharmony_ci 2273cb93a386Sopenharmony_ci auto layer = this->aboutToDraw(this, realPaint, &dst); 2274cb93a386Sopenharmony_ci if (layer) { 2275cb93a386Sopenharmony_ci this->topDevice()->drawImageLattice(image, lattice, dst, filter, layer->paint()); 2276cb93a386Sopenharmony_ci } 2277cb93a386Sopenharmony_ci} 2278cb93a386Sopenharmony_ci 2279cb93a386Sopenharmony_civoid SkCanvas::drawImage(const SkImage* image, SkScalar x, SkScalar y, 2280cb93a386Sopenharmony_ci const SkSamplingOptions& sampling, const SkPaint* paint) { 2281cb93a386Sopenharmony_ci TRACE_EVENT0("skia", TRACE_FUNC); 2282cb93a386Sopenharmony_ci RETURN_ON_NULL(image); 2283cb93a386Sopenharmony_ci this->onDrawImage2(image, x, y, sampling, paint); 2284cb93a386Sopenharmony_ci} 2285cb93a386Sopenharmony_ci 2286cb93a386Sopenharmony_civoid SkCanvas::drawImageRect(const SkImage* image, const SkRect& src, const SkRect& dst, 2287cb93a386Sopenharmony_ci const SkSamplingOptions& sampling, const SkPaint* paint, 2288cb93a386Sopenharmony_ci SrcRectConstraint constraint) { 2289cb93a386Sopenharmony_ci RETURN_ON_NULL(image); 2290cb93a386Sopenharmony_ci if (!fillable(dst) || !fillable(src)) { 2291cb93a386Sopenharmony_ci return; 2292cb93a386Sopenharmony_ci } 2293cb93a386Sopenharmony_ci this->onDrawImageRect2(image, src, dst, sampling, paint, constraint); 2294cb93a386Sopenharmony_ci} 2295cb93a386Sopenharmony_ci 2296cb93a386Sopenharmony_civoid SkCanvas::drawImageRect(const SkImage* image, const SkRect& dst, 2297cb93a386Sopenharmony_ci const SkSamplingOptions& sampling, const SkPaint* paint) { 2298cb93a386Sopenharmony_ci RETURN_ON_NULL(image); 2299cb93a386Sopenharmony_ci this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()), dst, sampling, 2300cb93a386Sopenharmony_ci paint, kFast_SrcRectConstraint); 2301cb93a386Sopenharmony_ci} 2302cb93a386Sopenharmony_ci 2303cb93a386Sopenharmony_civoid SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y, 2304cb93a386Sopenharmony_ci const SkPaint& paint) { 2305cb93a386Sopenharmony_ci auto glyphRunList = fScratchGlyphRunBuilder->blobToGlyphRunList(*blob, {x, y}); 2306cb93a386Sopenharmony_ci this->onDrawGlyphRunList(glyphRunList, paint); 2307cb93a386Sopenharmony_ci} 2308cb93a386Sopenharmony_ci 2309cb93a386Sopenharmony_civoid SkCanvas::onDrawGlyphRunList(const SkGlyphRunList& glyphRunList, const SkPaint& paint) { 2310cb93a386Sopenharmony_ci SkRect bounds = glyphRunList.sourceBounds(); 2311cb93a386Sopenharmony_ci if (this->internalQuickReject(bounds, paint)) { 2312cb93a386Sopenharmony_ci return; 2313cb93a386Sopenharmony_ci } 2314cb93a386Sopenharmony_ci auto layer = this->aboutToDraw(this, paint, &bounds); 2315cb93a386Sopenharmony_ci if (layer) { 2316cb93a386Sopenharmony_ci this->topDevice()->drawGlyphRunList(glyphRunList, layer->paint()); 2317cb93a386Sopenharmony_ci } 2318cb93a386Sopenharmony_ci} 2319cb93a386Sopenharmony_ci 2320cb93a386Sopenharmony_ci// These call the (virtual) onDraw... method 2321cb93a386Sopenharmony_civoid SkCanvas::drawSimpleText(const void* text, size_t byteLength, SkTextEncoding encoding, 2322cb93a386Sopenharmony_ci SkScalar x, SkScalar y, const SkFont& font, const SkPaint& paint) { 2323cb93a386Sopenharmony_ci TRACE_EVENT0("skia", TRACE_FUNC); 2324cb93a386Sopenharmony_ci if (byteLength) { 2325cb93a386Sopenharmony_ci sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength)); 2326cb93a386Sopenharmony_ci const SkGlyphRunList& glyphRunList = 2327cb93a386Sopenharmony_ci fScratchGlyphRunBuilder->textToGlyphRunList( 2328cb93a386Sopenharmony_ci font, paint, text, byteLength, {x, y}, encoding); 2329cb93a386Sopenharmony_ci if (!glyphRunList.empty()) { 2330cb93a386Sopenharmony_ci this->onDrawGlyphRunList(glyphRunList, paint); 2331cb93a386Sopenharmony_ci } 2332cb93a386Sopenharmony_ci } 2333cb93a386Sopenharmony_ci} 2334cb93a386Sopenharmony_ci 2335cb93a386Sopenharmony_civoid SkCanvas::drawGlyphs(int count, const SkGlyphID* glyphs, const SkPoint* positions, 2336cb93a386Sopenharmony_ci const uint32_t* clusters, int textByteCount, const char* utf8text, 2337cb93a386Sopenharmony_ci SkPoint origin, const SkFont& font, const SkPaint& paint) { 2338cb93a386Sopenharmony_ci if (count <= 0) { return; } 2339cb93a386Sopenharmony_ci 2340cb93a386Sopenharmony_ci SkGlyphRun glyphRun { 2341cb93a386Sopenharmony_ci font, 2342cb93a386Sopenharmony_ci SkMakeSpan(positions, count), 2343cb93a386Sopenharmony_ci SkMakeSpan(glyphs, count), 2344cb93a386Sopenharmony_ci SkMakeSpan(utf8text, textByteCount), 2345cb93a386Sopenharmony_ci SkMakeSpan(clusters, count), 2346cb93a386Sopenharmony_ci SkSpan<SkVector>() 2347cb93a386Sopenharmony_ci }; 2348cb93a386Sopenharmony_ci SkGlyphRunList glyphRunList { 2349cb93a386Sopenharmony_ci glyphRun, 2350cb93a386Sopenharmony_ci glyphRun.sourceBounds(paint).makeOffset(origin), 2351cb93a386Sopenharmony_ci origin 2352cb93a386Sopenharmony_ci }; 2353cb93a386Sopenharmony_ci this->onDrawGlyphRunList(glyphRunList, paint); 2354cb93a386Sopenharmony_ci} 2355cb93a386Sopenharmony_ci 2356cb93a386Sopenharmony_civoid SkCanvas::drawGlyphs(int count, const SkGlyphID glyphs[], const SkPoint positions[], 2357cb93a386Sopenharmony_ci SkPoint origin, const SkFont& font, const SkPaint& paint) { 2358cb93a386Sopenharmony_ci if (count <= 0) { return; } 2359cb93a386Sopenharmony_ci 2360cb93a386Sopenharmony_ci SkGlyphRun glyphRun { 2361cb93a386Sopenharmony_ci font, 2362cb93a386Sopenharmony_ci SkMakeSpan(positions, count), 2363cb93a386Sopenharmony_ci SkMakeSpan(glyphs, count), 2364cb93a386Sopenharmony_ci SkSpan<const char>(), 2365cb93a386Sopenharmony_ci SkSpan<const uint32_t>(), 2366cb93a386Sopenharmony_ci SkSpan<SkVector>() 2367cb93a386Sopenharmony_ci }; 2368cb93a386Sopenharmony_ci SkGlyphRunList glyphRunList { 2369cb93a386Sopenharmony_ci glyphRun, 2370cb93a386Sopenharmony_ci glyphRun.sourceBounds(paint).makeOffset(origin), 2371cb93a386Sopenharmony_ci origin 2372cb93a386Sopenharmony_ci }; 2373cb93a386Sopenharmony_ci this->onDrawGlyphRunList(glyphRunList, paint); 2374cb93a386Sopenharmony_ci} 2375cb93a386Sopenharmony_ci 2376cb93a386Sopenharmony_civoid SkCanvas::drawGlyphs(int count, const SkGlyphID glyphs[], const SkRSXform xforms[], 2377cb93a386Sopenharmony_ci SkPoint origin, const SkFont& font, const SkPaint& paint) { 2378cb93a386Sopenharmony_ci if (count <= 0) { return; } 2379cb93a386Sopenharmony_ci 2380cb93a386Sopenharmony_ci auto [positions, rotateScales] = 2381cb93a386Sopenharmony_ci fScratchGlyphRunBuilder->convertRSXForm(SkMakeSpan(xforms, count)); 2382cb93a386Sopenharmony_ci 2383cb93a386Sopenharmony_ci SkGlyphRun glyphRun { 2384cb93a386Sopenharmony_ci font, 2385cb93a386Sopenharmony_ci positions, 2386cb93a386Sopenharmony_ci SkMakeSpan(glyphs, count), 2387cb93a386Sopenharmony_ci SkSpan<const char>(), 2388cb93a386Sopenharmony_ci SkSpan<const uint32_t>(), 2389cb93a386Sopenharmony_ci rotateScales 2390cb93a386Sopenharmony_ci }; 2391cb93a386Sopenharmony_ci SkGlyphRunList glyphRunList { 2392cb93a386Sopenharmony_ci glyphRun, 2393cb93a386Sopenharmony_ci glyphRun.sourceBounds(paint).makeOffset(origin), 2394cb93a386Sopenharmony_ci origin 2395cb93a386Sopenharmony_ci }; 2396cb93a386Sopenharmony_ci this->onDrawGlyphRunList(glyphRunList, paint); 2397cb93a386Sopenharmony_ci} 2398cb93a386Sopenharmony_ci 2399cb93a386Sopenharmony_civoid SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y, 2400cb93a386Sopenharmony_ci const SkPaint& paint) { 2401cb93a386Sopenharmony_ci TRACE_EVENT0("skia", TRACE_FUNC); 2402cb93a386Sopenharmony_ci RETURN_ON_NULL(blob); 2403cb93a386Sopenharmony_ci RETURN_ON_FALSE(blob->bounds().makeOffset(x, y).isFinite()); 2404cb93a386Sopenharmony_ci 2405cb93a386Sopenharmony_ci // Overflow if more than 2^21 glyphs stopping a buffer overflow latter in the stack. 2406cb93a386Sopenharmony_ci // See chromium:1080481 2407cb93a386Sopenharmony_ci // TODO: can consider unrolling a few at a time if this limit becomes a problem. 2408cb93a386Sopenharmony_ci int totalGlyphCount = 0; 2409cb93a386Sopenharmony_ci constexpr int kMaxGlyphCount = 1 << 21; 2410cb93a386Sopenharmony_ci SkTextBlob::Iter i(*blob); 2411cb93a386Sopenharmony_ci SkTextBlob::Iter::Run r; 2412cb93a386Sopenharmony_ci while (i.next(&r)) { 2413cb93a386Sopenharmony_ci int glyphsLeft = kMaxGlyphCount - totalGlyphCount; 2414cb93a386Sopenharmony_ci RETURN_ON_FALSE(r.fGlyphCount <= glyphsLeft); 2415cb93a386Sopenharmony_ci totalGlyphCount += r.fGlyphCount; 2416cb93a386Sopenharmony_ci } 2417cb93a386Sopenharmony_ci this->onDrawTextBlob(blob, x, y, paint); 2418cb93a386Sopenharmony_ci} 2419cb93a386Sopenharmony_ci 2420cb93a386Sopenharmony_civoid SkCanvas::onDrawVerticesObject(const SkVertices* vertices, SkBlendMode bmode, 2421cb93a386Sopenharmony_ci const SkPaint& paint) { 2422cb93a386Sopenharmony_ci SkPaint simplePaint = clean_paint_for_drawVertices(paint); 2423cb93a386Sopenharmony_ci 2424cb93a386Sopenharmony_ci const SkRect& bounds = vertices->bounds(); 2425cb93a386Sopenharmony_ci if (this->internalQuickReject(bounds, simplePaint)) { 2426cb93a386Sopenharmony_ci return; 2427cb93a386Sopenharmony_ci } 2428cb93a386Sopenharmony_ci 2429cb93a386Sopenharmony_ci auto layer = this->aboutToDraw(this, simplePaint, &bounds); 2430cb93a386Sopenharmony_ci if (layer) { 2431cb93a386Sopenharmony_ci this->topDevice()->drawVertices(vertices, bmode, layer->paint()); 2432cb93a386Sopenharmony_ci } 2433cb93a386Sopenharmony_ci} 2434cb93a386Sopenharmony_ci 2435cb93a386Sopenharmony_civoid SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4], 2436cb93a386Sopenharmony_ci const SkPoint texCoords[4], SkBlendMode bmode, 2437cb93a386Sopenharmony_ci const SkPaint& paint) { 2438cb93a386Sopenharmony_ci TRACE_EVENT0("skia", TRACE_FUNC); 2439cb93a386Sopenharmony_ci if (nullptr == cubics) { 2440cb93a386Sopenharmony_ci return; 2441cb93a386Sopenharmony_ci } 2442cb93a386Sopenharmony_ci 2443cb93a386Sopenharmony_ci this->onDrawPatch(cubics, colors, texCoords, bmode, paint); 2444cb93a386Sopenharmony_ci} 2445cb93a386Sopenharmony_ci 2446cb93a386Sopenharmony_civoid SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4], 2447cb93a386Sopenharmony_ci const SkPoint texCoords[4], SkBlendMode bmode, 2448cb93a386Sopenharmony_ci const SkPaint& paint) { 2449cb93a386Sopenharmony_ci // drawPatch has the same behavior restrictions as drawVertices 2450cb93a386Sopenharmony_ci SkPaint simplePaint = clean_paint_for_drawVertices(paint); 2451cb93a386Sopenharmony_ci 2452cb93a386Sopenharmony_ci // Since a patch is always within the convex hull of the control points, we discard it when its 2453cb93a386Sopenharmony_ci // bounding rectangle is completely outside the current clip. 2454cb93a386Sopenharmony_ci SkRect bounds; 2455cb93a386Sopenharmony_ci bounds.setBounds(cubics, SkPatchUtils::kNumCtrlPts); 2456cb93a386Sopenharmony_ci if (this->internalQuickReject(bounds, simplePaint)) { 2457cb93a386Sopenharmony_ci return; 2458cb93a386Sopenharmony_ci } 2459cb93a386Sopenharmony_ci 2460cb93a386Sopenharmony_ci auto layer = this->aboutToDraw(this, simplePaint, &bounds); 2461cb93a386Sopenharmony_ci if (layer) { 2462cb93a386Sopenharmony_ci this->topDevice()->drawPatch(cubics, colors, texCoords, bmode, layer->paint()); 2463cb93a386Sopenharmony_ci } 2464cb93a386Sopenharmony_ci} 2465cb93a386Sopenharmony_ci 2466cb93a386Sopenharmony_civoid SkCanvas::drawDrawable(SkDrawable* dr, SkScalar x, SkScalar y) { 2467cb93a386Sopenharmony_ci#ifndef SK_BUILD_FOR_ANDROID_FRAMEWORK 2468cb93a386Sopenharmony_ci TRACE_EVENT0("skia", TRACE_FUNC); 2469cb93a386Sopenharmony_ci#endif 2470cb93a386Sopenharmony_ci RETURN_ON_NULL(dr); 2471cb93a386Sopenharmony_ci if (x || y) { 2472cb93a386Sopenharmony_ci SkMatrix matrix = SkMatrix::Translate(x, y); 2473cb93a386Sopenharmony_ci this->onDrawDrawable(dr, &matrix); 2474cb93a386Sopenharmony_ci } else { 2475cb93a386Sopenharmony_ci this->onDrawDrawable(dr, nullptr); 2476cb93a386Sopenharmony_ci } 2477cb93a386Sopenharmony_ci} 2478cb93a386Sopenharmony_ci 2479cb93a386Sopenharmony_civoid SkCanvas::drawDrawable(SkDrawable* dr, const SkMatrix* matrix) { 2480cb93a386Sopenharmony_ci#ifndef SK_BUILD_FOR_ANDROID_FRAMEWORK 2481cb93a386Sopenharmony_ci TRACE_EVENT0("skia", TRACE_FUNC); 2482cb93a386Sopenharmony_ci#endif 2483cb93a386Sopenharmony_ci RETURN_ON_NULL(dr); 2484cb93a386Sopenharmony_ci if (matrix && matrix->isIdentity()) { 2485cb93a386Sopenharmony_ci matrix = nullptr; 2486cb93a386Sopenharmony_ci } 2487cb93a386Sopenharmony_ci this->onDrawDrawable(dr, matrix); 2488cb93a386Sopenharmony_ci} 2489cb93a386Sopenharmony_ci 2490cb93a386Sopenharmony_civoid SkCanvas::onDrawDrawable(SkDrawable* dr, const SkMatrix* matrix) { 2491cb93a386Sopenharmony_ci // drawable bounds are no longer reliable (e.g. android displaylist) 2492cb93a386Sopenharmony_ci // so don't use them for quick-reject 2493cb93a386Sopenharmony_ci if (this->predrawNotify()) { 2494cb93a386Sopenharmony_ci this->topDevice()->drawDrawable(dr, matrix, this); 2495cb93a386Sopenharmony_ci } 2496cb93a386Sopenharmony_ci} 2497cb93a386Sopenharmony_ci 2498cb93a386Sopenharmony_civoid SkCanvas::onDrawAtlas2(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[], 2499cb93a386Sopenharmony_ci const SkColor colors[], int count, SkBlendMode bmode, 2500cb93a386Sopenharmony_ci const SkSamplingOptions& sampling, const SkRect* cull, 2501cb93a386Sopenharmony_ci const SkPaint* paint) { 2502cb93a386Sopenharmony_ci // drawAtlas is a combination of drawVertices and drawImage... 2503cb93a386Sopenharmony_ci SkPaint realPaint = clean_paint_for_drawVertices(clean_paint_for_drawImage(paint)); 2504cb93a386Sopenharmony_ci realPaint.setShader(atlas->makeShader(sampling)); 2505cb93a386Sopenharmony_ci 2506cb93a386Sopenharmony_ci if (cull && this->internalQuickReject(*cull, realPaint)) { 2507cb93a386Sopenharmony_ci return; 2508cb93a386Sopenharmony_ci } 2509cb93a386Sopenharmony_ci 2510cb93a386Sopenharmony_ci auto layer = this->aboutToDraw(this, realPaint); 2511cb93a386Sopenharmony_ci if (layer) { 2512cb93a386Sopenharmony_ci this->topDevice()->drawAtlas(xform, tex, colors, count, bmode, layer->paint()); 2513cb93a386Sopenharmony_ci } 2514cb93a386Sopenharmony_ci} 2515cb93a386Sopenharmony_ci 2516cb93a386Sopenharmony_civoid SkCanvas::onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) { 2517cb93a386Sopenharmony_ci SkASSERT(key); 2518cb93a386Sopenharmony_ci 2519cb93a386Sopenharmony_ci if (this->predrawNotify()) { 2520cb93a386Sopenharmony_ci this->topDevice()->drawAnnotation(rect, key, value); 2521cb93a386Sopenharmony_ci } 2522cb93a386Sopenharmony_ci} 2523cb93a386Sopenharmony_ci 2524cb93a386Sopenharmony_civoid SkCanvas::onDrawEdgeAAQuad(const SkRect& r, const SkPoint clip[4], QuadAAFlags edgeAA, 2525cb93a386Sopenharmony_ci const SkColor4f& color, SkBlendMode mode) { 2526cb93a386Sopenharmony_ci SkASSERT(r.isSorted()); 2527cb93a386Sopenharmony_ci 2528cb93a386Sopenharmony_ci SkPaint paint{color}; 2529cb93a386Sopenharmony_ci paint.setBlendMode(mode); 2530cb93a386Sopenharmony_ci if (this->internalQuickReject(r, paint)) { 2531cb93a386Sopenharmony_ci return; 2532cb93a386Sopenharmony_ci } 2533cb93a386Sopenharmony_ci 2534cb93a386Sopenharmony_ci if (this->predrawNotify()) { 2535cb93a386Sopenharmony_ci this->topDevice()->drawEdgeAAQuad(r, clip, edgeAA, color, mode); 2536cb93a386Sopenharmony_ci } 2537cb93a386Sopenharmony_ci} 2538cb93a386Sopenharmony_ci 2539cb93a386Sopenharmony_civoid SkCanvas::onDrawEdgeAAImageSet2(const ImageSetEntry imageSet[], int count, 2540cb93a386Sopenharmony_ci const SkPoint dstClips[], const SkMatrix preViewMatrices[], 2541cb93a386Sopenharmony_ci const SkSamplingOptions& sampling, const SkPaint* paint, 2542cb93a386Sopenharmony_ci SrcRectConstraint constraint) { 2543cb93a386Sopenharmony_ci if (count <= 0) { 2544cb93a386Sopenharmony_ci // Nothing to draw 2545cb93a386Sopenharmony_ci return; 2546cb93a386Sopenharmony_ci } 2547cb93a386Sopenharmony_ci 2548cb93a386Sopenharmony_ci SkPaint realPaint = clean_paint_for_drawImage(paint); 2549cb93a386Sopenharmony_ci 2550cb93a386Sopenharmony_ci // We could calculate the set's dstRect union to always check quickReject(), but we can't reject 2551cb93a386Sopenharmony_ci // individual entries and Chromium's occlusion culling already makes it likely that at least one 2552cb93a386Sopenharmony_ci // entry will be visible. So, we only calculate the draw bounds when it's trivial (count == 1), 2553cb93a386Sopenharmony_ci // or we need it for the autolooper (since it greatly improves image filter perf). 2554cb93a386Sopenharmony_ci bool needsAutoLayer = SkToBool(realPaint.getImageFilter()); 2555cb93a386Sopenharmony_ci bool setBoundsValid = count == 1 || needsAutoLayer; 2556cb93a386Sopenharmony_ci SkRect setBounds = imageSet[0].fDstRect; 2557cb93a386Sopenharmony_ci if (imageSet[0].fMatrixIndex >= 0) { 2558cb93a386Sopenharmony_ci // Account for the per-entry transform that is applied prior to the CTM when drawing 2559cb93a386Sopenharmony_ci preViewMatrices[imageSet[0].fMatrixIndex].mapRect(&setBounds); 2560cb93a386Sopenharmony_ci } 2561cb93a386Sopenharmony_ci if (needsAutoLayer) { 2562cb93a386Sopenharmony_ci for (int i = 1; i < count; ++i) { 2563cb93a386Sopenharmony_ci SkRect entryBounds = imageSet[i].fDstRect; 2564cb93a386Sopenharmony_ci if (imageSet[i].fMatrixIndex >= 0) { 2565cb93a386Sopenharmony_ci preViewMatrices[imageSet[i].fMatrixIndex].mapRect(&entryBounds); 2566cb93a386Sopenharmony_ci } 2567cb93a386Sopenharmony_ci setBounds.joinPossiblyEmptyRect(entryBounds); 2568cb93a386Sopenharmony_ci } 2569cb93a386Sopenharmony_ci } 2570cb93a386Sopenharmony_ci 2571cb93a386Sopenharmony_ci // If we happen to have the draw bounds, though, might as well check quickReject(). 2572cb93a386Sopenharmony_ci if (setBoundsValid && this->internalQuickReject(setBounds, realPaint)) { 2573cb93a386Sopenharmony_ci return; 2574cb93a386Sopenharmony_ci } 2575cb93a386Sopenharmony_ci 2576cb93a386Sopenharmony_ci auto layer = this->aboutToDraw(this, realPaint, setBoundsValid ? &setBounds : nullptr); 2577cb93a386Sopenharmony_ci if (layer) { 2578cb93a386Sopenharmony_ci this->topDevice()->drawEdgeAAImageSet(imageSet, count, dstClips, preViewMatrices, sampling, 2579cb93a386Sopenharmony_ci layer->paint(), constraint); 2580cb93a386Sopenharmony_ci } 2581cb93a386Sopenharmony_ci} 2582cb93a386Sopenharmony_ci 2583cb93a386Sopenharmony_ci////////////////////////////////////////////////////////////////////////////// 2584cb93a386Sopenharmony_ci// These methods are NOT virtual, and therefore must call back into virtual 2585cb93a386Sopenharmony_ci// methods, rather than actually drawing themselves. 2586cb93a386Sopenharmony_ci////////////////////////////////////////////////////////////////////////////// 2587cb93a386Sopenharmony_ci 2588cb93a386Sopenharmony_civoid SkCanvas::drawColor(const SkColor4f& c, SkBlendMode mode) { 2589cb93a386Sopenharmony_ci SkPaint paint; 2590cb93a386Sopenharmony_ci paint.setColor(c); 2591cb93a386Sopenharmony_ci paint.setBlendMode(mode); 2592cb93a386Sopenharmony_ci this->drawPaint(paint); 2593cb93a386Sopenharmony_ci} 2594cb93a386Sopenharmony_ci 2595cb93a386Sopenharmony_civoid SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) { 2596cb93a386Sopenharmony_ci const SkPoint pt = { x, y }; 2597cb93a386Sopenharmony_ci this->drawPoints(kPoints_PointMode, 1, &pt, paint); 2598cb93a386Sopenharmony_ci} 2599cb93a386Sopenharmony_ci 2600cb93a386Sopenharmony_civoid SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1, const SkPaint& paint) { 2601cb93a386Sopenharmony_ci SkPoint pts[2]; 2602cb93a386Sopenharmony_ci pts[0].set(x0, y0); 2603cb93a386Sopenharmony_ci pts[1].set(x1, y1); 2604cb93a386Sopenharmony_ci this->drawPoints(kLines_PointMode, 2, pts, paint); 2605cb93a386Sopenharmony_ci} 2606cb93a386Sopenharmony_ci 2607cb93a386Sopenharmony_civoid SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius, const SkPaint& paint) { 2608cb93a386Sopenharmony_ci if (radius < 0) { 2609cb93a386Sopenharmony_ci radius = 0; 2610cb93a386Sopenharmony_ci } 2611cb93a386Sopenharmony_ci 2612cb93a386Sopenharmony_ci SkRect r; 2613cb93a386Sopenharmony_ci r.setLTRB(cx - radius, cy - radius, cx + radius, cy + radius); 2614cb93a386Sopenharmony_ci this->drawOval(r, paint); 2615cb93a386Sopenharmony_ci} 2616cb93a386Sopenharmony_ci 2617cb93a386Sopenharmony_civoid SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry, 2618cb93a386Sopenharmony_ci const SkPaint& paint) { 2619cb93a386Sopenharmony_ci if (rx > 0 && ry > 0) { 2620cb93a386Sopenharmony_ci SkRRect rrect; 2621cb93a386Sopenharmony_ci rrect.setRectXY(r, rx, ry); 2622cb93a386Sopenharmony_ci this->drawRRect(rrect, paint); 2623cb93a386Sopenharmony_ci } else { 2624cb93a386Sopenharmony_ci this->drawRect(r, paint); 2625cb93a386Sopenharmony_ci } 2626cb93a386Sopenharmony_ci} 2627cb93a386Sopenharmony_ci 2628cb93a386Sopenharmony_civoid SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle, 2629cb93a386Sopenharmony_ci SkScalar sweepAngle, bool useCenter, 2630cb93a386Sopenharmony_ci const SkPaint& paint) { 2631cb93a386Sopenharmony_ci TRACE_EVENT0("skia", TRACE_FUNC); 2632cb93a386Sopenharmony_ci if (oval.isEmpty() || !sweepAngle) { 2633cb93a386Sopenharmony_ci return; 2634cb93a386Sopenharmony_ci } 2635cb93a386Sopenharmony_ci this->onDrawArc(oval, startAngle, sweepAngle, useCenter, paint); 2636cb93a386Sopenharmony_ci} 2637cb93a386Sopenharmony_ci 2638cb93a386Sopenharmony_ci/////////////////////////////////////////////////////////////////////////////// 2639cb93a386Sopenharmony_ci#ifdef SK_DISABLE_SKPICTURE 2640cb93a386Sopenharmony_civoid SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {} 2641cb93a386Sopenharmony_ci 2642cb93a386Sopenharmony_ci 2643cb93a386Sopenharmony_civoid SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix, 2644cb93a386Sopenharmony_ci const SkPaint* paint) {} 2645cb93a386Sopenharmony_ci#else 2646cb93a386Sopenharmony_ci 2647cb93a386Sopenharmony_civoid SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) { 2648cb93a386Sopenharmony_ci TRACE_EVENT0("skia", TRACE_FUNC); 2649cb93a386Sopenharmony_ci RETURN_ON_NULL(picture); 2650cb93a386Sopenharmony_ci 2651cb93a386Sopenharmony_ci if (matrix && matrix->isIdentity()) { 2652cb93a386Sopenharmony_ci matrix = nullptr; 2653cb93a386Sopenharmony_ci } 2654cb93a386Sopenharmony_ci if (picture->approximateOpCount() <= kMaxPictureOpsToUnrollInsteadOfRef) { 2655cb93a386Sopenharmony_ci SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect()); 2656cb93a386Sopenharmony_ci picture->playback(this); 2657cb93a386Sopenharmony_ci } else { 2658cb93a386Sopenharmony_ci this->onDrawPicture(picture, matrix, paint); 2659cb93a386Sopenharmony_ci } 2660cb93a386Sopenharmony_ci} 2661cb93a386Sopenharmony_ci 2662cb93a386Sopenharmony_civoid SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix, 2663cb93a386Sopenharmony_ci const SkPaint* paint) { 2664cb93a386Sopenharmony_ci if (this->internalQuickReject(picture->cullRect(), paint ? *paint : SkPaint{}, matrix)) { 2665cb93a386Sopenharmony_ci return; 2666cb93a386Sopenharmony_ci } 2667cb93a386Sopenharmony_ci 2668cb93a386Sopenharmony_ci SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect()); 2669cb93a386Sopenharmony_ci picture->playback(this); 2670cb93a386Sopenharmony_ci} 2671cb93a386Sopenharmony_ci#endif 2672cb93a386Sopenharmony_ci 2673cb93a386Sopenharmony_ci/////////////////////////////////////////////////////////////////////////////// 2674cb93a386Sopenharmony_ci 2675cb93a386Sopenharmony_ciSkCanvas::ImageSetEntry::ImageSetEntry() = default; 2676cb93a386Sopenharmony_ciSkCanvas::ImageSetEntry::~ImageSetEntry() = default; 2677cb93a386Sopenharmony_ciSkCanvas::ImageSetEntry::ImageSetEntry(const ImageSetEntry&) = default; 2678cb93a386Sopenharmony_ciSkCanvas::ImageSetEntry& SkCanvas::ImageSetEntry::operator=(const ImageSetEntry&) = default; 2679cb93a386Sopenharmony_ci 2680cb93a386Sopenharmony_ciSkCanvas::ImageSetEntry::ImageSetEntry(sk_sp<const SkImage> image, const SkRect& srcRect, 2681cb93a386Sopenharmony_ci const SkRect& dstRect, int matrixIndex, float alpha, 2682cb93a386Sopenharmony_ci unsigned aaFlags, bool hasClip) 2683cb93a386Sopenharmony_ci : fImage(std::move(image)) 2684cb93a386Sopenharmony_ci , fSrcRect(srcRect) 2685cb93a386Sopenharmony_ci , fDstRect(dstRect) 2686cb93a386Sopenharmony_ci , fMatrixIndex(matrixIndex) 2687cb93a386Sopenharmony_ci , fAlpha(alpha) 2688cb93a386Sopenharmony_ci , fAAFlags(aaFlags) 2689cb93a386Sopenharmony_ci , fHasClip(hasClip) {} 2690cb93a386Sopenharmony_ci 2691cb93a386Sopenharmony_ciSkCanvas::ImageSetEntry::ImageSetEntry(sk_sp<const SkImage> image, const SkRect& srcRect, 2692cb93a386Sopenharmony_ci const SkRect& dstRect, float alpha, unsigned aaFlags) 2693cb93a386Sopenharmony_ci : fImage(std::move(image)) 2694cb93a386Sopenharmony_ci , fSrcRect(srcRect) 2695cb93a386Sopenharmony_ci , fDstRect(dstRect) 2696cb93a386Sopenharmony_ci , fAlpha(alpha) 2697cb93a386Sopenharmony_ci , fAAFlags(aaFlags) {} 2698cb93a386Sopenharmony_ci 2699cb93a386Sopenharmony_ci/////////////////////////////////////////////////////////////////////////////// 2700cb93a386Sopenharmony_ci 2701cb93a386Sopenharmony_cistd::unique_ptr<SkCanvas> SkCanvas::MakeRasterDirect(const SkImageInfo& info, void* pixels, 2702cb93a386Sopenharmony_ci size_t rowBytes, const SkSurfaceProps* props) { 2703cb93a386Sopenharmony_ci if (!SkSurfaceValidateRasterInfo(info, rowBytes)) { 2704cb93a386Sopenharmony_ci return nullptr; 2705cb93a386Sopenharmony_ci } 2706cb93a386Sopenharmony_ci 2707cb93a386Sopenharmony_ci SkBitmap bitmap; 2708cb93a386Sopenharmony_ci if (!bitmap.installPixels(info, pixels, rowBytes)) { 2709cb93a386Sopenharmony_ci return nullptr; 2710cb93a386Sopenharmony_ci } 2711cb93a386Sopenharmony_ci 2712cb93a386Sopenharmony_ci return props ? 2713cb93a386Sopenharmony_ci std::make_unique<SkCanvas>(bitmap, *props) : 2714cb93a386Sopenharmony_ci std::make_unique<SkCanvas>(bitmap); 2715cb93a386Sopenharmony_ci} 2716cb93a386Sopenharmony_ci 2717cb93a386Sopenharmony_ci/////////////////////////////////////////////////////////////////////////////// 2718cb93a386Sopenharmony_ci 2719cb93a386Sopenharmony_ciSkNoDrawCanvas::SkNoDrawCanvas(int width, int height) 2720cb93a386Sopenharmony_ci : INHERITED(SkIRect::MakeWH(width, height)) {} 2721cb93a386Sopenharmony_ci 2722cb93a386Sopenharmony_ciSkNoDrawCanvas::SkNoDrawCanvas(const SkIRect& bounds) 2723cb93a386Sopenharmony_ci : INHERITED(bounds) {} 2724cb93a386Sopenharmony_ci 2725cb93a386Sopenharmony_ciSkNoDrawCanvas::SkNoDrawCanvas(sk_sp<SkBaseDevice> device) 2726cb93a386Sopenharmony_ci : INHERITED(device) {} 2727cb93a386Sopenharmony_ci 2728cb93a386Sopenharmony_ciSkCanvas::SaveLayerStrategy SkNoDrawCanvas::getSaveLayerStrategy(const SaveLayerRec& rec) { 2729cb93a386Sopenharmony_ci (void)this->INHERITED::getSaveLayerStrategy(rec); 2730cb93a386Sopenharmony_ci return kNoLayer_SaveLayerStrategy; 2731cb93a386Sopenharmony_ci} 2732cb93a386Sopenharmony_ci 2733cb93a386Sopenharmony_cibool SkNoDrawCanvas::onDoSaveBehind(const SkRect*) { 2734cb93a386Sopenharmony_ci return false; 2735cb93a386Sopenharmony_ci} 2736cb93a386Sopenharmony_ci 2737cb93a386Sopenharmony_ci/////////////////////////////////////////////////////////////////////////////// 2738cb93a386Sopenharmony_ci 2739cb93a386Sopenharmony_cistatic_assert((int)SkRegion::kDifference_Op == (int)SkClipOp::kDifference, ""); 2740cb93a386Sopenharmony_cistatic_assert((int)SkRegion::kIntersect_Op == (int)SkClipOp::kIntersect, ""); 2741cb93a386Sopenharmony_ci 2742cb93a386Sopenharmony_ci/////////////////////////////////////////////////////////////////////////////////////////////////// 2743cb93a386Sopenharmony_ci 2744cb93a386Sopenharmony_ciSkRasterHandleAllocator::Handle SkCanvas::accessTopRasterHandle() const { 2745cb93a386Sopenharmony_ci const SkBaseDevice* dev = this->topDevice(); 2746cb93a386Sopenharmony_ci if (fAllocator) { 2747cb93a386Sopenharmony_ci SkRasterHandleAllocator::Handle handle = dev->getRasterHandle(); 2748cb93a386Sopenharmony_ci SkIRect clip = dev->devClipBounds(); 2749cb93a386Sopenharmony_ci if (!clip.intersect({0, 0, dev->width(), dev->height()})) { 2750cb93a386Sopenharmony_ci clip.setEmpty(); 2751cb93a386Sopenharmony_ci } 2752cb93a386Sopenharmony_ci 2753cb93a386Sopenharmony_ci fAllocator->updateHandle(handle, dev->localToDevice(), clip); 2754cb93a386Sopenharmony_ci return handle; 2755cb93a386Sopenharmony_ci } 2756cb93a386Sopenharmony_ci return nullptr; 2757cb93a386Sopenharmony_ci} 2758cb93a386Sopenharmony_ci 2759cb93a386Sopenharmony_cistatic bool install(SkBitmap* bm, const SkImageInfo& info, 2760cb93a386Sopenharmony_ci const SkRasterHandleAllocator::Rec& rec) { 2761cb93a386Sopenharmony_ci return bm->installPixels(info, rec.fPixels, rec.fRowBytes, rec.fReleaseProc, rec.fReleaseCtx); 2762cb93a386Sopenharmony_ci} 2763cb93a386Sopenharmony_ci 2764cb93a386Sopenharmony_ciSkRasterHandleAllocator::Handle SkRasterHandleAllocator::allocBitmap(const SkImageInfo& info, 2765cb93a386Sopenharmony_ci SkBitmap* bm) { 2766cb93a386Sopenharmony_ci SkRasterHandleAllocator::Rec rec; 2767cb93a386Sopenharmony_ci if (!this->allocHandle(info, &rec) || !install(bm, info, rec)) { 2768cb93a386Sopenharmony_ci return nullptr; 2769cb93a386Sopenharmony_ci } 2770cb93a386Sopenharmony_ci return rec.fHandle; 2771cb93a386Sopenharmony_ci} 2772cb93a386Sopenharmony_ci 2773cb93a386Sopenharmony_cistd::unique_ptr<SkCanvas> 2774cb93a386Sopenharmony_ciSkRasterHandleAllocator::MakeCanvas(std::unique_ptr<SkRasterHandleAllocator> alloc, 2775cb93a386Sopenharmony_ci const SkImageInfo& info, const Rec* rec) { 2776cb93a386Sopenharmony_ci if (!alloc || !SkSurfaceValidateRasterInfo(info, rec ? rec->fRowBytes : kIgnoreRowBytesValue)) { 2777cb93a386Sopenharmony_ci return nullptr; 2778cb93a386Sopenharmony_ci } 2779cb93a386Sopenharmony_ci 2780cb93a386Sopenharmony_ci SkBitmap bm; 2781cb93a386Sopenharmony_ci Handle hndl; 2782cb93a386Sopenharmony_ci 2783cb93a386Sopenharmony_ci if (rec) { 2784cb93a386Sopenharmony_ci hndl = install(&bm, info, *rec) ? rec->fHandle : nullptr; 2785cb93a386Sopenharmony_ci } else { 2786cb93a386Sopenharmony_ci hndl = alloc->allocBitmap(info, &bm); 2787cb93a386Sopenharmony_ci } 2788cb93a386Sopenharmony_ci return hndl ? std::unique_ptr<SkCanvas>(new SkCanvas(bm, std::move(alloc), hndl)) : nullptr; 2789cb93a386Sopenharmony_ci} 2790cb93a386Sopenharmony_ci 2791cb93a386Sopenharmony_cistd::array<int, 2> SkCanvas::CalcHpsBluredImageDimension(const SkBlurArg& blurArg) 2792cb93a386Sopenharmony_ci{ 2793cb93a386Sopenharmony_ci#if SK_SUPPORT_GPU 2794cb93a386Sopenharmony_ci auto dContext = GrAsDirectContext(this->recordingContext()); 2795cb93a386Sopenharmony_ci if (dContext) { 2796cb93a386Sopenharmony_ci return dContext->CalcHpsBluredImageDimension(blurArg); 2797cb93a386Sopenharmony_ci } 2798cb93a386Sopenharmony_ci#endif 2799cb93a386Sopenharmony_ci return {0, 0}; 2800cb93a386Sopenharmony_ci} 2801cb93a386Sopenharmony_ci 2802cb93a386Sopenharmony_cibool SkCanvas::onDrawBlurImage(const SkImage* image, const SkBlurArg& blurArg) 2803cb93a386Sopenharmony_ci{ 2804cb93a386Sopenharmony_ci return this->topDevice()->drawBlurImage(image, blurArg); 2805cb93a386Sopenharmony_ci} 2806cb93a386Sopenharmony_ci 2807cb93a386Sopenharmony_ci/////////////////////////////////////////////////////////////////////////////////////////////////// 2808