fc93eb0171
TBR=reed@google.com NOTRY=true Bug: skia: Change-Id: I85e3712dac621f1714cda2ecb86980ff9305c43c Reviewed-on: https://skia-review.googlesource.com/c/172742 Reviewed-by: Cary Clark <caryclark@skia.org> Commit-Queue: Cary Clark <caryclark@skia.org> Auto-Submit: Cary Clark <caryclark@skia.org>
4762 lines
147 KiB
Plaintext
4762 lines
147 KiB
Plaintext
#Topic Canvas
|
|
#Alias Canvas_Reference ##
|
|
|
|
#Class SkCanvas
|
|
|
|
#Code
|
|
#Populate
|
|
##
|
|
|
|
Canvas provides an interface for drawing, and how the drawing is clipped and transformed.
|
|
Canvas contains a stack of Matrix and Clip values.
|
|
|
|
Canvas and Paint together provide the state to draw into Surface or Device.
|
|
Each Canvas draw call transforms the geometry of the object by the concatenation of all
|
|
Matrix values in the stack. The transformed geometry is clipped by the intersection
|
|
of all of Clip values in the stack. The Canvas draw calls use Paint to supply drawing
|
|
state such as Color, Typeface, text size, stroke width, Shader and so on.
|
|
|
|
To draw to a pixel-based destination, create Raster_Surface or GPU_Surface.
|
|
Request Canvas from Surface to obtain the interface to draw.
|
|
Canvas generated by Raster_Surface draws to memory visible to the CPU.
|
|
Canvas generated by GPU_Surface uses Vulkan or OpenGL to draw to the GPU.
|
|
|
|
To draw to a document, obtain Canvas from SVG_Canvas, Document_PDF, or Picture_Recorder.
|
|
Document based Canvas and other Canvas subclasses reference Device describing the
|
|
destination.
|
|
|
|
Canvas can be constructed to draw to Bitmap without first creating Raster_Surface.
|
|
This approach may be deprecated in the future.
|
|
|
|
Canvas may be created directly when no Surface is required; some Canvas methods
|
|
implicitly create Raster_Surface.
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
#Method static std::unique_ptr<SkCanvas> MakeRasterDirect(const SkImageInfo& info, void* pixels,
|
|
size_t rowBytes,
|
|
const SkSurfaceProps* props = nullptr)
|
|
#In Constructors
|
|
#Line # creates from SkImageInfo and Pixel_Storage ##
|
|
#Populate
|
|
|
|
#Example
|
|
#Description
|
|
Allocates a three by three bitmap, clears it to white, and draws a black pixel
|
|
in the center.
|
|
##
|
|
void draw(SkCanvas* ) {
|
|
SkImageInfo info = SkImageInfo::MakeN32Premul(3, 3); // device aligned, 32 bpp, Premultiplied
|
|
const size_t minRowBytes = info.minRowBytes(); // bytes used by one bitmap row
|
|
const size_t size = info.computeMinByteSize(); // bytes used by all rows
|
|
SkAutoTMalloc<SkPMColor> storage(size); // allocate storage for pixels
|
|
SkPMColor* pixels = storage.get(); // get pointer to allocated storage
|
|
// create a SkCanvas backed by a raster device, and delete it when the
|
|
// function goes out of scope.
|
|
std::unique_ptr<SkCanvas> canvas = SkCanvas::MakeRasterDirect(info, pixels, minRowBytes);
|
|
canvas->clear(SK_ColorWHITE); // white is Unpremultiplied, in ARGB order
|
|
canvas->flush(); // ensure that pixels are cleared
|
|
SkPMColor pmWhite = pixels[0]; // the Premultiplied format may vary
|
|
SkPaint paint; // by default, draws black
|
|
canvas->drawPoint(1, 1, paint); // draw in the center
|
|
canvas->flush(); // ensure that point was drawn
|
|
for (int y = 0; y < info.height(); ++y) {
|
|
for (int x = 0; x < info.width(); ++x) {
|
|
SkDebugf("%c", *pixels++ == pmWhite ? '-' : 'x');
|
|
}
|
|
SkDebugf("\n");
|
|
}
|
|
}
|
|
#StdOut
|
|
---
|
|
-x-
|
|
---
|
|
##
|
|
##
|
|
|
|
#SeeAlso MakeRasterDirectN32 SkSurface::MakeRasterDirect
|
|
|
|
##
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
#Method static std::unique_ptr<SkCanvas> MakeRasterDirectN32(int width, int height, SkPMColor* pixels,
|
|
size_t rowBytes)
|
|
#In Constructors
|
|
#Line # creates from image data and Pixel_Storage ##
|
|
#Populate
|
|
|
|
#Example
|
|
#Description
|
|
Allocates a three by three bitmap, clears it to white, and draws a black pixel
|
|
in the center.
|
|
##
|
|
void draw(SkCanvas* ) {
|
|
const int width = 3;
|
|
const int height = 3;
|
|
SkPMColor pixels[height][width]; // allocate a 3 by 3 Premultiplied bitmap on the stack
|
|
// create a SkCanvas backed by a raster device, and delete it when the
|
|
// function goes out of scope.
|
|
std::unique_ptr<SkCanvas> canvas = SkCanvas::MakeRasterDirectN32(
|
|
width,
|
|
height,
|
|
pixels[0], // top-left of the bitmap
|
|
sizeof(pixels[0])); // byte width of the each row
|
|
// write a Premultiplied value for white into all pixels in the bitmap
|
|
canvas->clear(SK_ColorWHITE);
|
|
SkPMColor pmWhite = pixels[0][0]; // the Premultiplied format may vary
|
|
SkPaint paint; // by default, draws black
|
|
canvas->drawPoint(1, 1, paint); // draw in the center
|
|
canvas->flush(); // ensure that pixels is ready to be read
|
|
for (int y = 0; y < height; ++y) {
|
|
for (int x = 0; x < width; ++x) {
|
|
SkDebugf("%c", pixels[y][x] == pmWhite ? '-' : 'x');
|
|
}
|
|
SkDebugf("\n");
|
|
}
|
|
}
|
|
#StdOut
|
|
---
|
|
-x-
|
|
---
|
|
##
|
|
##
|
|
|
|
#SeeAlso MakeRasterDirect SkSurface::MakeRasterDirect SkImageInfo::MakeN32Premul
|
|
|
|
##
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
#Method SkCanvas()
|
|
|
|
#Line # creates with no Surface, no dimensions ##
|
|
#Populate
|
|
|
|
#Example
|
|
|
|
#Description
|
|
Passes a placeholder to a function that requires one.
|
|
##
|
|
|
|
#Function
|
|
static void check_for_rotated_ctm(const SkCanvas* canvas) {
|
|
const SkMatrix& matrix = canvas->getTotalMatrix();
|
|
SkDebugf("rect stays rect is %s\n", matrix.rectStaysRect() ? "true" : "false");
|
|
}
|
|
|
|
##
|
|
void draw(SkCanvas* canvas) {
|
|
check_for_rotated_ctm(canvas);
|
|
canvas->rotate(30);
|
|
check_for_rotated_ctm(canvas);
|
|
|
|
SkCanvas defaultCanvas;
|
|
check_for_rotated_ctm(&defaultCanvas);
|
|
}
|
|
|
|
#StdOut
|
|
rect stays rect is true
|
|
rect stays rect is false
|
|
rect stays rect is true
|
|
##
|
|
##
|
|
|
|
#SeeAlso MakeRasterDirect SkRasterHandleAllocator::MakeCanvas SkSurface::getCanvas SkCreateColorSpaceXformCanvas
|
|
|
|
##
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
#Method SkCanvas(int width, int height, const SkSurfaceProps* props = nullptr)
|
|
|
|
#Line # creates with no Surface, set dimensions, Surface_Properties ##
|
|
#Populate
|
|
|
|
#Example
|
|
SkCanvas canvas(10, 20); // 10 units wide, 20 units high
|
|
canvas.clipRect(SkRect::MakeXYWH(30, 40, 5, 10)); // clip is outside canvas' device
|
|
SkDebugf("canvas %s empty\n", canvas.getDeviceClipBounds().isEmpty() ? "is" : "is not");
|
|
|
|
#StdOut
|
|
canvas is empty
|
|
##
|
|
##
|
|
|
|
#SeeAlso MakeRasterDirect SkSurfaceProps SkPixelGeometry SkCreateColorSpaceXformCanvas
|
|
|
|
##
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
#Method explicit SkCanvas(const SkBitmap& bitmap)
|
|
|
|
#Line # uses existing Bitmap ##
|
|
#Populate
|
|
|
|
#Example
|
|
#Description
|
|
The actual output depends on the installed fonts.
|
|
##
|
|
SkBitmap bitmap;
|
|
// create a bitmap 5 wide and 11 high
|
|
bitmap.allocPixels(SkImageInfo::MakeN32Premul(5, 11));
|
|
SkCanvas canvas(bitmap);
|
|
canvas.clear(SK_ColorWHITE); // white is Unpremultiplied, in ARGB order
|
|
SkPixmap pixmap; // provides guaranteed access to the drawn pixels
|
|
if (!canvas.peekPixels(&pixmap)) {
|
|
SkDebugf("peekPixels should never fail.\n");
|
|
}
|
|
const SkPMColor* pixels = pixmap.addr32(); // points to top-left of bitmap
|
|
SkPMColor pmWhite = pixels[0]; // the Premultiplied format may vary
|
|
SkPaint paint; // by default, draws black, 12 point text
|
|
canvas.drawString("!", 1, 10, paint); // 1 char at baseline (1, 10)
|
|
for (int y = 0; y < bitmap.height(); ++y) {
|
|
for (int x = 0; x < bitmap.width(); ++x) {
|
|
SkDebugf("%c", *pixels++ == pmWhite ? '-' : 'x');
|
|
}
|
|
SkDebugf("\n");
|
|
}
|
|
|
|
#StdOut
|
|
-----
|
|
---x-
|
|
---x-
|
|
---x-
|
|
---x-
|
|
---x-
|
|
---x-
|
|
-----
|
|
---x-
|
|
---x-
|
|
-----
|
|
#StdOut ##
|
|
##
|
|
|
|
#SeeAlso MakeRasterDirect SkRasterHandleAllocator::MakeCanvas SkSurface::getCanvas SkCreateColorSpaceXformCanvas
|
|
|
|
##
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
#Method SkCanvas(const SkBitmap& bitmap, const SkSurfaceProps& props)
|
|
|
|
#Line # uses existing Bitmap and Surface_Properties ##
|
|
#Populate
|
|
|
|
#Example
|
|
#Description
|
|
The actual output depends on the installed fonts.
|
|
##
|
|
SkBitmap bitmap;
|
|
// create a bitmap 5 wide and 11 high
|
|
bitmap.allocPixels(SkImageInfo::MakeN32Premul(5, 11));
|
|
SkCanvas canvas(bitmap, SkSurfaceProps(0, kUnknown_SkPixelGeometry));
|
|
canvas.clear(SK_ColorWHITE); // white is Unpremultiplied, in ARGB order
|
|
SkPixmap pixmap; // provides guaranteed access to the drawn pixels
|
|
if (!canvas.peekPixels(&pixmap)) {
|
|
SkDebugf("peekPixels should never fail.\n");
|
|
}
|
|
const SkPMColor* pixels = pixmap.addr32(); // points to top-left of bitmap
|
|
SkPMColor pmWhite = pixels[0]; // the Premultiplied format may vary
|
|
SkPaint paint; // by default, draws black, 12 point text
|
|
canvas.drawString("!", 1, 10, paint); // 1 char at baseline (1, 10)
|
|
for (int y = 0; y < bitmap.height(); ++y) {
|
|
for (int x = 0; x < bitmap.width(); ++x) {
|
|
SkDebugf("%c", *pixels++ == pmWhite ? '-' : 'x');
|
|
}
|
|
SkDebugf("\n");
|
|
}
|
|
|
|
#StdOut
|
|
-----
|
|
---x-
|
|
---x-
|
|
---x-
|
|
---x-
|
|
---x-
|
|
---x-
|
|
-----
|
|
---x-
|
|
---x-
|
|
-----
|
|
#StdOut ##
|
|
##
|
|
|
|
#SeeAlso MakeRasterDirect SkRasterHandleAllocator::MakeCanvas SkSurface::getCanvas SkCreateColorSpaceXformCanvas
|
|
|
|
##
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
#Method virtual ~SkCanvas()
|
|
|
|
#Line # draws saved Layers, frees resources ##
|
|
#Populate
|
|
|
|
#Example
|
|
#Description
|
|
Canvas Layer draws into bitmap. saveLayerAlpha sets up an additional
|
|
drawing surface that blends with the bitmap. When Layer goes out of
|
|
scope, Layer destructor is called. The saved Layer is restored, drawing
|
|
transparent letters.
|
|
##
|
|
void draw(SkCanvas* canvas) {
|
|
SkBitmap bitmap;
|
|
bitmap.allocPixels(SkImageInfo::MakeN32Premul(200, 200));
|
|
{
|
|
SkCanvas offscreen(bitmap);
|
|
SkPaint paint;
|
|
paint.setTextSize(100);
|
|
offscreen.drawString("ABC", 20, 160, paint);
|
|
SkRect layerBounds = SkRect::MakeXYWH(32, 32, 192, 192);
|
|
offscreen.saveLayerAlpha(&layerBounds, 128);
|
|
offscreen.clear(SK_ColorWHITE);
|
|
offscreen.drawString("DEF", 20, 160, paint);
|
|
}
|
|
canvas->drawBitmap(bitmap, 0, 0, nullptr);
|
|
}
|
|
##
|
|
|
|
#SeeAlso State_Stack
|
|
|
|
##
|
|
|
|
# ------------------------------------------------------------------------------
|
|
#Subtopic Property
|
|
#Line # metrics and attributes ##
|
|
##
|
|
|
|
#Method SkMetaData& getMetaData()
|
|
#In Property
|
|
#In Utility
|
|
#Line # associates additional data with the canvas ##
|
|
#Populate
|
|
|
|
#Example
|
|
const char* kHelloMetaData = "HelloMetaData";
|
|
SkCanvas canvas;
|
|
SkMetaData& metaData = canvas.getMetaData();
|
|
SkDebugf("before: %s\n", metaData.findString(kHelloMetaData));
|
|
metaData.setString(kHelloMetaData, "Hello!");
|
|
SkDebugf("during: %s\n", metaData.findString(kHelloMetaData));
|
|
metaData.removeString(kHelloMetaData);
|
|
SkDebugf("after: %s\n", metaData.findString(kHelloMetaData));
|
|
|
|
#StdOut
|
|
before: (null)
|
|
during: Hello!
|
|
after: (null)
|
|
#StdOut ##
|
|
##
|
|
|
|
#SeeAlso SkMetaData
|
|
|
|
##
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
#Method SkImageInfo imageInfo() const
|
|
#In Property
|
|
#Line # returns Image_Info for Canvas ##
|
|
#Populate
|
|
|
|
#Example
|
|
SkCanvas emptyCanvas;
|
|
SkImageInfo canvasInfo = emptyCanvas.imageInfo();
|
|
SkImageInfo emptyInfo;
|
|
SkDebugf("emptyInfo %c= canvasInfo\n", emptyInfo == canvasInfo ? '=' : '!');
|
|
|
|
#StdOut
|
|
emptyInfo == canvasInfo
|
|
##
|
|
##
|
|
|
|
#SeeAlso SkImageInfo MakeRasterDirect makeSurface
|
|
|
|
##
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
#Method bool getProps(SkSurfaceProps* props) const
|
|
#In Property
|
|
#Line # copies Surface_Properties if available ##
|
|
#Populate
|
|
|
|
#Example
|
|
SkBitmap bitmap;
|
|
SkCanvas canvas(bitmap, SkSurfaceProps(0, kRGB_V_SkPixelGeometry));
|
|
SkSurfaceProps surfaceProps(0, kUnknown_SkPixelGeometry);
|
|
SkDebugf("isRGB:%d\n", SkPixelGeometryIsRGB(surfaceProps.pixelGeometry()));
|
|
if (!canvas.getProps(&surfaceProps)) {
|
|
SkDebugf("getProps failed unexpectedly.\n");
|
|
}
|
|
SkDebugf("isRGB:%d\n", SkPixelGeometryIsRGB(surfaceProps.pixelGeometry()));
|
|
|
|
#StdOut
|
|
isRGB:0
|
|
isRGB:1
|
|
#StdOut ##
|
|
##
|
|
|
|
#SeeAlso SkSurfaceProps makeSurface
|
|
|
|
##
|
|
|
|
# ------------------------------------------------------------------------------
|
|
#Subtopic Utility
|
|
#Line # rarely called management functions ##
|
|
##
|
|
|
|
#Method void flush()
|
|
#In Utility
|
|
#Line # triggers execution of all pending draw operations ##
|
|
#Populate
|
|
|
|
#NoExample
|
|
##
|
|
|
|
#SeeAlso peekPixels SkSurface::flush GrContext::flush GrContext::abandonContext
|
|
|
|
##
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
#Method virtual SkISize getBaseLayerSize() const
|
|
#In Property
|
|
#Line # returns size of base Layer in global coordinates ##
|
|
#Populate
|
|
|
|
#Example
|
|
SkBitmap bitmap;
|
|
bitmap.allocPixels(SkImageInfo::MakeN32Premul(20, 30));
|
|
SkCanvas canvas(bitmap, SkSurfaceProps(0, kUnknown_SkPixelGeometry));
|
|
canvas.clipRect(SkRect::MakeWH(10, 40));
|
|
SkIRect clipDeviceBounds = canvas.getDeviceClipBounds();
|
|
if (clipDeviceBounds.isEmpty()) {
|
|
SkDebugf("Empty clip bounds is unexpected!\n");
|
|
}
|
|
SkDebugf("clip=%d,%d\n", clipDeviceBounds.width(), clipDeviceBounds.height());
|
|
SkISize baseLayerSize = canvas.getBaseLayerSize();
|
|
SkDebugf("size=%d,%d\n", baseLayerSize.width(), baseLayerSize.height());
|
|
|
|
#StdOut
|
|
clip=10,30
|
|
size=20,30
|
|
##
|
|
##
|
|
|
|
#ToDo is this the same as the width and height of surface? ##
|
|
|
|
#SeeAlso getDeviceClipBounds
|
|
|
|
##
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
#Method sk_sp<SkSurface> makeSurface(const SkImageInfo& info, const SkSurfaceProps* props = nullptr)
|
|
#In Constructors
|
|
#Line # creates Surface matching SkImageInfo and SkSurfaceProps ##
|
|
#Populate
|
|
|
|
#Example
|
|
sk_sp<SkSurface> surface = SkSurface::MakeRasterN32Premul(5, 6);
|
|
SkCanvas* smallCanvas = surface->getCanvas();
|
|
SkImageInfo imageInfo = SkImageInfo::MakeN32Premul(3, 4);
|
|
sk_sp<SkSurface> compatible = smallCanvas->makeSurface(imageInfo);
|
|
SkDebugf("compatible %c= nullptr\n", compatible == nullptr ? '=' : '!');
|
|
SkDebugf("size = %d, %d\n", compatible->width(), compatible->height());
|
|
|
|
#StdOut
|
|
compatible != nullptr
|
|
size = 3, 4
|
|
##
|
|
##
|
|
|
|
#SeeAlso SkSurface SkSurface::makeSurface SkImageInfo SkSurfaceProps
|
|
|
|
##
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
#Method virtual GrContext* getGrContext()
|
|
#In Property
|
|
#Line # returns GPU_Context of the GPU_Surface ##
|
|
#Populate
|
|
|
|
#Example
|
|
void draw(SkCanvas* canvas) {
|
|
if (canvas->getGrContext()) {
|
|
canvas->clear(SK_ColorRED);
|
|
} else {
|
|
canvas->clear(SK_ColorBLUE);
|
|
}
|
|
}
|
|
##
|
|
|
|
#ToDo fiddle should show both CPU and GPU out ##
|
|
|
|
#SeeAlso GrContext
|
|
|
|
##
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
#Method void* accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin = nullptr)
|
|
#In Utility
|
|
#In Property
|
|
#Line # returns writable pixel access if available ##
|
|
#Populate
|
|
|
|
#Example
|
|
void draw(SkCanvas* canvas) {
|
|
if (canvas->accessTopLayerPixels(nullptr, nullptr)) {
|
|
canvas->clear(SK_ColorRED);
|
|
} else {
|
|
canvas->clear(SK_ColorBLUE);
|
|
}
|
|
}
|
|
##
|
|
|
|
#Example
|
|
#Description
|
|
Draws "ABC" on the device. Then draws "DEF" in Layer, and reads
|
|
Layer to add a large dotted "DEF". Finally blends Layer with the
|
|
device.
|
|
|
|
The Layer and blended result appear on the CPU and GPU but the large dotted
|
|
"DEF" appear only on the CPU.
|
|
##
|
|
void draw(SkCanvas* canvas) {
|
|
SkPaint paint;
|
|
paint.setTextSize(100);
|
|
canvas->drawString("ABC", 20, 160, paint);
|
|
SkRect layerBounds = SkRect::MakeXYWH(32, 32, 192, 192);
|
|
canvas->saveLayerAlpha(&layerBounds, 128);
|
|
canvas->clear(SK_ColorWHITE);
|
|
canvas->drawString("DEF", 20, 160, paint);
|
|
SkImageInfo imageInfo;
|
|
size_t rowBytes;
|
|
SkIPoint origin;
|
|
uint32_t* access = (uint32_t*) canvas->accessTopLayerPixels(&imageInfo, &rowBytes, &origin);
|
|
if (access) {
|
|
int h = imageInfo.height();
|
|
int v = imageInfo.width();
|
|
int rowWords = rowBytes / sizeof(uint32_t);
|
|
for (int y = 0; y < h; ++y) {
|
|
int newY = (y - h / 2) * 2 + h / 2;
|
|
if (newY < 0 || newY >= h) {
|
|
continue;
|
|
}
|
|
for (int x = 0; x < v; ++x) {
|
|
int newX = (x - v / 2) * 2 + v / 2;
|
|
if (newX < 0 || newX >= v) {
|
|
continue;
|
|
}
|
|
if (access[y * rowWords + x] == SK_ColorBLACK) {
|
|
access[newY * rowWords + newX] = SK_ColorGRAY;
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
canvas->restore();
|
|
}
|
|
##
|
|
|
|
#ToDo there are no callers of this that I can find. Deprecate? ##
|
|
#ToDo fiddle should show both CPU and GPU out ##
|
|
|
|
#SeeAlso SkImageInfo SkPixmap
|
|
|
|
##
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
#Method SkRasterHandleAllocator::Handle accessTopRasterHandle() const
|
|
#In Utility
|
|
#In Property
|
|
#Line # returns context that tracks Clip and Matrix ##
|
|
#Populate
|
|
|
|
#Example
|
|
#Description
|
|
#ToDo ##
|
|
##
|
|
#Function
|
|
static void DeleteCallback(void*, void* context) {
|
|
delete (char*) context;
|
|
}
|
|
|
|
class CustomAllocator : public SkRasterHandleAllocator {
|
|
public:
|
|
bool allocHandle(const SkImageInfo& info, Rec* rec) override {
|
|
char* context = new char[4]{'s', 'k', 'i', 'a'};
|
|
rec->fReleaseProc = DeleteCallback;
|
|
rec->fReleaseCtx = context;
|
|
rec->fHandle = context;
|
|
rec->fPixels = context;
|
|
rec->fRowBytes = 4;
|
|
return true;
|
|
}
|
|
|
|
void updateHandle(Handle handle, const SkMatrix& ctm, const SkIRect& clip_bounds) override {
|
|
// apply canvas matrix and clip to custom environment
|
|
}
|
|
};
|
|
|
|
##
|
|
void draw(SkCanvas* canvas) {
|
|
const SkImageInfo info = SkImageInfo::MakeN32Premul(1, 1);
|
|
std::unique_ptr<SkCanvas> c2 =
|
|
SkRasterHandleAllocator::MakeCanvas(std::unique_ptr<CustomAllocator>(
|
|
new CustomAllocator()), info);
|
|
char* context = (char*) c2->accessTopRasterHandle();
|
|
SkDebugf("context = %.4s\n", context);
|
|
|
|
}
|
|
#StdOut
|
|
context = skia
|
|
##
|
|
#ToDo skstd::make_unique could not be used because def is private -- note to fix in c++14? ##
|
|
##
|
|
|
|
#SeeAlso SkRasterHandleAllocator
|
|
|
|
##
|
|
|
|
# ------------------------------------------------------------------------------
|
|
#Subtopic Pixels
|
|
#Line # read and write pixel values ##
|
|
##
|
|
|
|
#Method bool peekPixels(SkPixmap* pixmap)
|
|
#In Pixels
|
|
#Line # returns if Canvas has direct access to its pixels ##
|
|
#Populate
|
|
|
|
#Example
|
|
SkPixmap pixmap;
|
|
if (canvas->peekPixels(&pixmap)) {
|
|
SkDebugf("width=%d height=%d\n", pixmap.bounds().width(), pixmap.bounds().height());
|
|
}
|
|
#StdOut
|
|
width=256 height=256
|
|
##
|
|
##
|
|
|
|
#SeeAlso readPixels SkBitmap::peekPixels SkImage::peekPixels SkSurface::peekPixels
|
|
|
|
##
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
#Method bool readPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes,
|
|
int srcX, int srcY)
|
|
#In Pixels
|
|
#Line # copies and converts rectangle of pixels from Canvas ##
|
|
|
|
Copies Rect of pixels from Canvas into dstPixels. Matrix and Clip are
|
|
ignored.
|
|
|
|
Source Rect corners are (srcX, srcY) and (imageInfo().width(), imageInfo().height()).
|
|
Destination Rect corners are (0, 0) and (dstInfo.width(), dstInfo.height()).
|
|
Copies each readable pixel intersecting both rectangles, without scaling,
|
|
converting to dstInfo.colorType() and dstInfo.alphaType() if required.
|
|
|
|
Pixels are readable when Device is raster, or backed by a GPU.
|
|
Pixels are not readable when SkCanvas is returned by SkDocument::beginPage,
|
|
returned by SkPictureRecorder::beginRecording, or Canvas is the base of a utility
|
|
class like SkDebugCanvas.
|
|
|
|
The destination pixel storage must be allocated by the caller.
|
|
|
|
Pixel values are converted only if Color_Type and Alpha_Type
|
|
do not match. Only pixels within both source and destination rectangles
|
|
are copied. dstPixels contents outside Rect intersection are unchanged.
|
|
|
|
Pass negative values for srcX or srcY to offset pixels across or down destination.
|
|
|
|
Does not copy, and returns false if:
|
|
|
|
#List
|
|
# Source and destination rectangles do not intersect. ##
|
|
# Canvas pixels could not be converted to dstInfo.colorType() or dstInfo.alphaType(). ##
|
|
# Canvas pixels are not readable; for instance, Canvas is document-based. ##
|
|
# dstRowBytes is too small to contain one row of pixels. ##
|
|
##
|
|
|
|
#Param dstInfo width, height, Color_Type, and Alpha_Type of dstPixels ##
|
|
#Param dstPixels storage for pixels; dstInfo.height() times dstRowBytes, or larger ##
|
|
#Param dstRowBytes size of one destination row; dstInfo.width() times pixel size, or larger ##
|
|
#Param srcX offset into readable pixels on x-axis; may be negative ##
|
|
#Param srcY offset into readable pixels on y-axis; may be negative ##
|
|
|
|
#Return true if pixels were copied ##
|
|
|
|
#Example
|
|
#Width 64
|
|
#Height 64
|
|
#Description
|
|
A black circle drawn on a blue background provides an image to copy.
|
|
readPixels copies one quarter of the canvas into each of the four corners.
|
|
The copied quarter circles overdraw the original circle.
|
|
##
|
|
canvas->clear(SK_ColorBLUE);
|
|
SkPaint paint;
|
|
canvas->drawCircle(32, 32, 28, paint);
|
|
SkImageInfo info = SkImageInfo::Make(64, 64, kBGRA_8888_SkColorType, kPremul_SkAlphaType);
|
|
sk_sp<SkData> data(SkData::MakeUninitialized(info.minRowBytes() * info.height()));
|
|
sk_bzero(data->writable_data(), info.minRowBytes() * info.height());
|
|
for (int x : { 32, -32 } ) {
|
|
for (int y : { 32, -32 } ) {
|
|
canvas->readPixels(info, data->writable_data(), info.minRowBytes(), x, y);
|
|
}
|
|
}
|
|
sk_sp<SkImage> image = SkImage::MakeRasterData(info, data, info.minRowBytes());
|
|
canvas->drawImage(image, 0, 0);
|
|
##
|
|
|
|
#Example
|
|
#Description
|
|
Canvas returned by Raster_Surface has Premultiplied pixel values.
|
|
clear() takes Unpremultiplied input with Color_Alpha equal 0x80
|
|
and RGB equal 0x55, 0xAA, 0xFF. RGB is multiplied by Color_Alpha
|
|
to generate Premultiplied value 0x802B5580. readPixels converts pixel back
|
|
to Unpremultiplied value 0x8056A9FF, introducing error.
|
|
##
|
|
canvas->clear(0x8055aaff);
|
|
for (SkAlphaType alphaType : { kPremul_SkAlphaType, kUnpremul_SkAlphaType } ) {
|
|
uint32_t pixel = 0;
|
|
SkImageInfo info = SkImageInfo::Make(1, 1, kBGRA_8888_SkColorType, alphaType);
|
|
if (canvas->readPixels(info, &pixel, 4, 0, 0)) {
|
|
SkDebugf("pixel = %08x\n", pixel);
|
|
}
|
|
}
|
|
|
|
#StdOut
|
|
pixel = 802b5580
|
|
pixel = 8056a9ff
|
|
##
|
|
##
|
|
|
|
#SeeAlso peekPixels writePixels drawBitmap drawImage SkBitmap::readPixels SkPixmap::readPixels SkImage::readPixels SkSurface::readPixels
|
|
|
|
##
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
#Method bool readPixels(const SkPixmap& pixmap, int srcX, int srcY)
|
|
|
|
Copies Rect of pixels from Canvas into pixmap. Matrix and Clip are
|
|
ignored.
|
|
|
|
Source Rect corners are (srcX, srcY) and (imageInfo().width(), imageInfo().height()).
|
|
Destination Rect corners are (0, 0) and (pixmap.width(), pixmap.height()).
|
|
Copies each readable pixel intersecting both rectangles, without scaling,
|
|
converting to pixmap.colorType() and pixmap.alphaType() if required.
|
|
|
|
Pixels are readable when Device is raster, or backed by a GPU.
|
|
Pixels are not readable when SkCanvas is returned by SkDocument::beginPage,
|
|
returned by SkPictureRecorder::beginRecording, or Canvas is the base of a utility
|
|
class like SkDebugCanvas.
|
|
|
|
Caller must allocate pixel storage in pixmap if needed.
|
|
|
|
Pixel values are converted only if Color_Type and Alpha_Type
|
|
do not match. Only pixels within both source and destination Rects
|
|
are copied. pixmap pixels contents outside Rect intersection are unchanged.
|
|
|
|
Pass negative values for srcX or srcY to offset pixels across or down pixmap.
|
|
|
|
Does not copy, and returns false if:
|
|
|
|
#List
|
|
# Source and destination rectangles do not intersect. ##
|
|
# Canvas pixels could not be converted to pixmap.colorType() or pixmap.alphaType(). ##
|
|
# Canvas pixels are not readable; for instance, Canvas is document-based. ##
|
|
# Pixmap pixels could not be allocated. ##
|
|
# pixmap.rowBytes() is too small to contain one row of pixels. ##
|
|
##
|
|
|
|
#Param pixmap storage for pixels copied from Canvas ##
|
|
#Param srcX offset into readable pixels on x-axis; may be negative ##
|
|
#Param srcY offset into readable pixels on y-axis; may be negative ##
|
|
|
|
#Return true if pixels were copied ##
|
|
|
|
#Example
|
|
#Description
|
|
clear() takes Unpremultiplied input with Color_Alpha equal 0x80
|
|
and RGB equal 0x55, 0xAA, 0xFF. RGB is multiplied by Color_Alpha
|
|
to generate Premultiplied value 0x802B5580.
|
|
##
|
|
void draw(SkCanvas* canvas) {
|
|
canvas->clear(0x8055aaff);
|
|
uint32_t pixels[1] = { 0 };
|
|
SkPixmap pixmap(SkImageInfo::MakeN32Premul(1, 1), pixels, 4);
|
|
canvas->readPixels(pixmap, 0, 0);
|
|
SkDebugf("pixel = %08x\n", pixels[0]);
|
|
}
|
|
#StdOut
|
|
pixel = 802b5580
|
|
##
|
|
##
|
|
|
|
#SeeAlso peekPixels writePixels drawBitmap drawImage SkBitmap::readPixels SkPixmap::readPixels SkImage::readPixels SkSurface::readPixels
|
|
|
|
##
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
#Method bool readPixels(const SkBitmap& bitmap, int srcX, int srcY)
|
|
|
|
Copies Rect of pixels from Canvas into bitmap. Matrix and Clip are
|
|
ignored.
|
|
|
|
Source Rect corners are (srcX, srcY) and (imageInfo().width(), imageInfo().height()).
|
|
Destination Rect corners are (0, 0) and (bitmap.width(), bitmap.height()).
|
|
Copies each readable pixel intersecting both rectangles, without scaling,
|
|
converting to bitmap.colorType() and bitmap.alphaType() if required.
|
|
|
|
Pixels are readable when Device is raster, or backed by a GPU.
|
|
Pixels are not readable when SkCanvas is returned by SkDocument::beginPage,
|
|
returned by SkPictureRecorder::beginRecording, or Canvas is the base of a utility
|
|
class like SkDebugCanvas.
|
|
|
|
Caller must allocate pixel storage in bitmap if needed.
|
|
|
|
Bitmap values are converted only if Color_Type and Alpha_Type
|
|
do not match. Only pixels within both source and destination rectangles
|
|
are copied. Bitmap pixels outside Rect intersection are unchanged.
|
|
|
|
Pass negative values for srcX or srcY to offset pixels across or down bitmap.
|
|
|
|
Does not copy, and returns false if:
|
|
|
|
#List
|
|
# Source and destination rectangles do not intersect. ##
|
|
# Canvas pixels could not be converted to bitmap.colorType() or bitmap.alphaType(). ##
|
|
# Canvas pixels are not readable; for instance, Canvas is document-based. ##
|
|
# bitmap pixels could not be allocated. ##
|
|
# bitmap.rowBytes() is too small to contain one row of pixels. ##
|
|
##
|
|
|
|
#Param bitmap storage for pixels copied from Canvas ##
|
|
#Param srcX offset into readable pixels on x-axis; may be negative ##
|
|
#Param srcY offset into readable pixels on y-axis; may be negative ##
|
|
|
|
#Return true if pixels were copied ##
|
|
|
|
#Example
|
|
#Description
|
|
clear() takes Unpremultiplied input with Color_Alpha equal 0x80
|
|
and RGB equal 0x55, 0xAA, 0xFF. RGB is multiplied by Color_Alpha
|
|
to generate Premultiplied value 0x802B5580.
|
|
##
|
|
void draw(SkCanvas* canvas) {
|
|
canvas->clear(0x8055aaff);
|
|
SkBitmap bitmap;
|
|
bitmap.allocPixels(SkImageInfo::MakeN32Premul(1, 1));
|
|
canvas->readPixels(bitmap, 0, 0);
|
|
SkDebugf("pixel = %08x\n", bitmap.getAddr32(0, 0)[0]);
|
|
}
|
|
#StdOut
|
|
pixel = 802b5580
|
|
##
|
|
##
|
|
|
|
#SeeAlso peekPixels writePixels drawBitmap drawImage SkBitmap::readPixels SkPixmap::readPixels SkImage::readPixels SkSurface::readPixels
|
|
|
|
##
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
#Method bool writePixels(const SkImageInfo& info, const void* pixels, size_t rowBytes, int x, int y)
|
|
#In Pixels
|
|
#Line # copies and converts rectangle of pixels to Canvas ##
|
|
Copies Rect from pixels to Canvas. Matrix and Clip are ignored.
|
|
Source Rect corners are (0, 0) and (info.width(), info.height()).
|
|
Destination Rect corners are (x, y) and
|
|
(imageInfo().width(), imageInfo().height()).
|
|
|
|
Copies each readable pixel intersecting both rectangles, without scaling,
|
|
converting to imageInfo().colorType() and imageInfo().alphaType() if required.
|
|
|
|
Pixels are writable when Device is raster, or backed by a GPU.
|
|
Pixels are not writable when SkCanvas is returned by SkDocument::beginPage,
|
|
returned by SkPictureRecorder::beginRecording, or Canvas is the base of a utility
|
|
class like SkDebugCanvas.
|
|
|
|
Pixel values are converted only if Color_Type and Alpha_Type
|
|
do not match. Only pixels within both source and destination rectangles
|
|
are copied. Canvas pixels outside Rect intersection are unchanged.
|
|
|
|
Pass negative values for x or y to offset pixels to the left or
|
|
above Canvas pixels.
|
|
|
|
Does not copy, and returns false if:
|
|
|
|
#List
|
|
# Source and destination rectangles do not intersect. ##
|
|
# pixels could not be converted to Canvas imageInfo().colorType() or
|
|
imageInfo().alphaType(). ##
|
|
# Canvas pixels are not writable; for instance, Canvas is document-based. ##
|
|
# rowBytes is too small to contain one row of pixels. ##
|
|
##
|
|
|
|
#Param info width, height, Color_Type, and Alpha_Type of pixels ##
|
|
#Param pixels pixels to copy, of size info.height() times rowBytes, or larger ##
|
|
#Param rowBytes size of one row of pixels; info.width() times pixel size, or larger ##
|
|
#Param x offset into Canvas writable pixels on x-axis; may be negative ##
|
|
#Param y offset into Canvas writable pixels on y-axis; may be negative ##
|
|
|
|
#Return true if pixels were written to Canvas ##
|
|
|
|
#Example
|
|
SkImageInfo imageInfo = SkImageInfo::MakeN32(256, 1, kPremul_SkAlphaType);
|
|
for (int y = 0; y < 256; ++y) {
|
|
uint32_t pixels[256];
|
|
for (int x = 0; x < 256; ++x) {
|
|
pixels[x] = SkColorSetARGB(x, x + y, x, x - y);
|
|
}
|
|
canvas->writePixels(imageInfo, &pixels, sizeof(pixels), 0, y);
|
|
}
|
|
##
|
|
|
|
#SeeAlso readPixels drawBitmap drawImage SkBitmap::writePixels
|
|
|
|
##
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
#Method bool writePixels(const SkBitmap& bitmap, int x, int y)
|
|
|
|
Copies Rect from pixels to Canvas. Matrix and Clip are ignored.
|
|
Source Rect corners are (0, 0) and (bitmap.width(), bitmap.height()).
|
|
|
|
Destination Rect corners are (x, y) and
|
|
(imageInfo().width(), imageInfo().height()).
|
|
|
|
Copies each readable pixel intersecting both rectangles, without scaling,
|
|
converting to imageInfo().colorType() and imageInfo().alphaType() if required.
|
|
|
|
Pixels are writable when Device is raster, or backed by a GPU.
|
|
Pixels are not writable when SkCanvas is returned by SkDocument::beginPage,
|
|
returned by SkPictureRecorder::beginRecording, or Canvas is the base of a utility
|
|
class like SkDebugCanvas.
|
|
|
|
Pixel values are converted only if Color_Type and Alpha_Type
|
|
do not match. Only pixels within both source and destination rectangles
|
|
are copied. Canvas pixels outside Rect intersection are unchanged.
|
|
|
|
Pass negative values for x or y to offset pixels to the left or
|
|
above Canvas pixels.
|
|
|
|
Does not copy, and returns false if:
|
|
|
|
#List
|
|
# Source and destination rectangles do not intersect. ##
|
|
# bitmap does not have allocated pixels. ##
|
|
# bitmap pixels could not be converted to Canvas imageInfo().colorType() or
|
|
imageInfo().alphaType(). ##
|
|
# Canvas pixels are not writable; for instance, Canvas is document based. ##
|
|
# bitmap pixels are inaccessible; for instance, bitmap wraps a texture. ##
|
|
##
|
|
|
|
#Param bitmap contains pixels copied to Canvas ##
|
|
#Param x offset into Canvas writable pixels in x; may be negative ##
|
|
#Param y offset into Canvas writable pixels in y; may be negative ##
|
|
|
|
#Return true if pixels were written to Canvas ##
|
|
|
|
#Example
|
|
void draw(SkCanvas* canvas) {
|
|
SkImageInfo imageInfo = SkImageInfo::MakeN32Premul(2, 2);
|
|
SkBitmap bitmap;
|
|
bitmap.setInfo(imageInfo);
|
|
uint32_t pixels[4];
|
|
bitmap.setPixels(pixels);
|
|
for (int y = 0; y < 256; y += 2) {
|
|
for (int x = 0; x < 256; x += 2) {
|
|
pixels[0] = SkColorSetRGB(x, y, x | y);
|
|
pixels[1] = SkColorSetRGB(x ^ y, y, x);
|
|
pixels[2] = SkColorSetRGB(x, x & y, y);
|
|
pixels[3] = SkColorSetRGB(~x, ~y, x);
|
|
canvas->writePixels(bitmap, x, y);
|
|
}
|
|
}
|
|
}
|
|
##
|
|
|
|
#SeeAlso readPixels drawBitmap drawImage SkBitmap::writePixels
|
|
|
|
##
|
|
|
|
# ------------------------------------------------------------------------------
|
|
#Subtopic State_Stack
|
|
#Line # stack of state for hierarchical drawing ##
|
|
|
|
Canvas maintains a stack of state that allows hierarchical drawing, commonly used
|
|
to implement windows and views. The initial state has an identity matrix and and
|
|
an infinite clip. Even with a wide-open clip, drawing is constrained by the
|
|
bounds of the Canvas Surface or Device.
|
|
|
|
Canvas savable state consists of Clip and Matrix.
|
|
Clip describes the area that may be drawn to.
|
|
Matrix transforms the geometry.
|
|
|
|
save(), saveLayer, saveLayerPreserveLCDTextRequests, and saveLayerAlpha
|
|
save state and return the depth of the stack.
|
|
|
|
restore(), restoreToCount, and ~SkCanvas() revert state to its value when saved.
|
|
|
|
Each state on the stack intersects Clip with the previous Clip,
|
|
and concatenates Matrix with the previous Matrix.
|
|
The intersected Clip makes the drawing area the same or smaller;
|
|
the concatenated Matrix may move the origin and potentially scale or rotate
|
|
the coordinate space.
|
|
|
|
Canvas does not require balancing the state stack but it is a good idea
|
|
to do so. Calling save() without restore() will eventually cause Skia to fail;
|
|
mismatched save() and restore() create hard to find bugs.
|
|
|
|
It is not possible to use state to draw outside of the clip defined by the
|
|
previous state.
|
|
|
|
#Example
|
|
#Description
|
|
Draw to ever smaller clips; then restore drawing to full canvas.
|
|
Note that the second clipRect is not permitted to enlarge Clip.
|
|
##
|
|
#Height 160
|
|
void draw(SkCanvas* canvas) {
|
|
SkPaint paint;
|
|
canvas->save(); // records stack depth to restore
|
|
canvas->clipRect(SkRect::MakeWH(100, 100)); // constrains drawing to clip
|
|
canvas->clear(SK_ColorRED); // draws to limit of clip
|
|
canvas->save(); // records stack depth to restore
|
|
canvas->clipRect(SkRect::MakeWH(50, 150)); // Rect below 100 is ignored
|
|
canvas->clear(SK_ColorBLUE); // draws to smaller clip
|
|
canvas->restore(); // enlarges clip
|
|
canvas->drawLine(20, 20, 150, 150, paint); // line below 100 is not drawn
|
|
canvas->restore(); // enlarges clip
|
|
canvas->drawLine(150, 20, 50, 120, paint); // line below 100 is drawn
|
|
}
|
|
##
|
|
|
|
Each Clip uses the current Matrix for its coordinates.
|
|
|
|
#Example
|
|
#Description
|
|
While clipRect is given the same rectangle twice, Matrix makes the second
|
|
clipRect draw at half the size of the first.
|
|
##
|
|
#Height 128
|
|
void draw(SkCanvas* canvas) {
|
|
canvas->clipRect(SkRect::MakeWH(100, 100));
|
|
canvas->clear(SK_ColorRED);
|
|
canvas->scale(.5, .5);
|
|
canvas->clipRect(SkRect::MakeWH(100, 100));
|
|
canvas->clear(SK_ColorBLUE);
|
|
}
|
|
##
|
|
|
|
#SeeAlso save saveLayer saveLayerPreserveLCDTextRequests saveLayerAlpha restore() restoreToCount
|
|
|
|
#Method int save()
|
|
|
|
#In State_Stack
|
|
#Line # saves Clip and Matrix on stack ##
|
|
#Populate
|
|
|
|
#Example
|
|
#Description
|
|
The black square is translated 50 pixels down and to the right.
|
|
Restoring Canvas state removes translate() from Canvas stack;
|
|
the red square is not translated, and is drawn at the origin.
|
|
##
|
|
#Height 100
|
|
void draw(SkCanvas* canvas) {
|
|
SkPaint paint;
|
|
SkRect rect = { 0, 0, 25, 25 };
|
|
canvas->drawRect(rect, paint);
|
|
canvas->save();
|
|
canvas->translate(50, 50);
|
|
canvas->drawRect(rect, paint);
|
|
canvas->restore();
|
|
paint.setColor(SK_ColorRED);
|
|
canvas->drawRect(rect, paint);
|
|
}
|
|
##
|
|
|
|
#SeeAlso saveLayer saveLayerPreserveLCDTextRequests saveLayerAlpha restore restoreToCount
|
|
|
|
##
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
#Method void restore()
|
|
|
|
#In State_Stack
|
|
#Line # restores changes to Clip and Matrix, pops save stack ##
|
|
#Populate
|
|
|
|
#Example
|
|
void draw(SkCanvas* canvas) {
|
|
SkCanvas simple;
|
|
SkDebugf("depth = %d\n", simple.getSaveCount());
|
|
simple.restore();
|
|
SkDebugf("depth = %d\n", simple.getSaveCount());
|
|
}
|
|
##
|
|
|
|
#SeeAlso save saveLayer saveLayerPreserveLCDTextRequests saveLayerAlpha restoreToCount
|
|
|
|
##
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
#Method int getSaveCount() const
|
|
|
|
#In State_Stack
|
|
#Line # returns depth of stack containing Clip and Matrix ##
|
|
#Populate
|
|
|
|
#Example
|
|
void draw(SkCanvas* canvas) {
|
|
SkCanvas simple;
|
|
SkDebugf("depth = %d\n", simple.getSaveCount());
|
|
simple.save();
|
|
SkDebugf("depth = %d\n", simple.getSaveCount());
|
|
simple.restore();
|
|
SkDebugf("depth = %d\n", simple.getSaveCount());
|
|
}
|
|
#StdOut
|
|
depth = 1
|
|
depth = 2
|
|
depth = 1
|
|
##
|
|
##
|
|
|
|
#SeeAlso save restore restoreToCount
|
|
|
|
##
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
#Method void restoreToCount(int saveCount)
|
|
|
|
#In State_Stack
|
|
#Line # restores changes to Clip and Matrix to given depth ##
|
|
#Populate
|
|
|
|
#Example
|
|
void draw(SkCanvas* canvas) {
|
|
SkDebugf("depth = %d\n", canvas->getSaveCount());
|
|
canvas->save();
|
|
canvas->save();
|
|
SkDebugf("depth = %d\n", canvas->getSaveCount());
|
|
canvas->restoreToCount(0);
|
|
SkDebugf("depth = %d\n", canvas->getSaveCount());
|
|
}
|
|
#StdOut
|
|
depth = 1
|
|
depth = 3
|
|
depth = 1
|
|
##
|
|
##
|
|
|
|
#SeeAlso restore getSaveCount save
|
|
|
|
##
|
|
|
|
#Subtopic State_Stack ##
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
#Subtopic Layer
|
|
#Substitute layer
|
|
#Alias Layers
|
|
#Substitute layers
|
|
##
|
|
#Line # temporary Bitmap to draw into ##
|
|
|
|
Layer allocates a temporary Bitmap to draw into. When the drawing is
|
|
complete, the Bitmap is drawn into the Canvas.
|
|
|
|
Layer is saved in a stack along with other saved state. When state with a Layer
|
|
is restored, the Bitmap is drawn into the previous Layer.
|
|
|
|
Layer may be initialized with the contents of the previous Layer. When Layer is
|
|
restored, its Bitmap can be modified by Paint passed to Layer to apply
|
|
Color_Alpha, Color_Filter, Image_Filter, and Blend_Mode.
|
|
|
|
#Method int saveLayer(const SkRect* bounds, const SkPaint* paint)
|
|
|
|
#In Layer
|
|
#Line # saves Clip and Matrix on stack; creates Layer ##
|
|
#Populate
|
|
|
|
#Example
|
|
#Description
|
|
Rectangles are blurred by Image_Filter when restore() draws Layer to main
|
|
Canvas.
|
|
##
|
|
#Height 128
|
|
#Function
|
|
###$
|
|
#include "SkBlurImageFilter.h"
|
|
$$$#
|
|
##
|
|
|
|
void draw(SkCanvas* canvas) {
|
|
SkPaint paint, blur;
|
|
blur.setImageFilter(SkBlurImageFilter::Make(3, 3, nullptr));
|
|
canvas->saveLayer(nullptr, &blur);
|
|
SkRect rect = { 25, 25, 50, 50};
|
|
canvas->drawRect(rect, paint);
|
|
canvas->translate(50, 50);
|
|
paint.setColor(SK_ColorRED);
|
|
canvas->drawRect(rect, paint);
|
|
canvas->restore();
|
|
}
|
|
##
|
|
|
|
#SeeAlso save restore saveLayer saveLayerPreserveLCDTextRequests saveLayerAlpha SaveLayerRec
|
|
|
|
##
|
|
|
|
#Method int saveLayer(const SkRect& bounds, const SkPaint* paint)
|
|
|
|
#In Layer
|
|
#Populate
|
|
|
|
#Example
|
|
#Description
|
|
Rectangles are blurred by Image_Filter when restore() draws Layer to main Canvas.
|
|
The red rectangle is clipped; it does not fully fit on Layer.
|
|
Image_Filter blurs past edge of Layer so red rectangle is blurred on all sides.
|
|
##
|
|
#Height 128
|
|
#Function
|
|
###$
|
|
#include "SkBlurImageFilter.h"
|
|
$$$#
|
|
##
|
|
|
|
void draw(SkCanvas* canvas) {
|
|
SkPaint paint, blur;
|
|
blur.setImageFilter(SkBlurImageFilter::Make(3, 3, nullptr));
|
|
canvas->saveLayer(SkRect::MakeWH(90, 90), &blur);
|
|
SkRect rect = { 25, 25, 50, 50};
|
|
canvas->drawRect(rect, paint);
|
|
canvas->translate(50, 50);
|
|
paint.setColor(SK_ColorRED);
|
|
canvas->drawRect(rect, paint);
|
|
canvas->restore();
|
|
}
|
|
##
|
|
|
|
#SeeAlso save restore saveLayerPreserveLCDTextRequests saveLayerAlpha SaveLayerRec
|
|
|
|
##
|
|
|
|
#Method int saveLayerPreserveLCDTextRequests(const SkRect* bounds, const SkPaint* paint)
|
|
|
|
#In Layer
|
|
#Line # saves Clip and Matrix on stack; creates Layer for LCD text ##
|
|
#Populate
|
|
|
|
#Example
|
|
SkPaint paint;
|
|
paint.setAntiAlias(true);
|
|
paint.setLCDRenderText(true);
|
|
paint.setTextSize(20);
|
|
for (auto preserve : { false, true } ) {
|
|
preserve ? canvas->saveLayerPreserveLCDTextRequests(nullptr, nullptr)
|
|
: canvas->saveLayer(nullptr, nullptr);
|
|
SkPaint p;
|
|
p.setColor(SK_ColorWHITE);
|
|
// Comment out the next line to draw on a non-opaque background.
|
|
canvas->drawRect(SkRect::MakeLTRB(25, 40, 200, 70), p);
|
|
canvas->drawString("Hamburgefons", 30, 60, paint);
|
|
|
|
p.setColor(0xFFCCCCCC);
|
|
canvas->drawRect(SkRect::MakeLTRB(25, 70, 200, 100), p);
|
|
canvas->drawString("Hamburgefons", 30, 90, paint);
|
|
|
|
canvas->restore();
|
|
canvas->translate(0, 80);
|
|
}
|
|
##
|
|
|
|
#SeeAlso save restore saveLayer saveLayerAlpha SaveLayerRec
|
|
|
|
##
|
|
|
|
#Method int saveLayerAlpha(const SkRect* bounds, U8CPU alpha)
|
|
|
|
#In Layer
|
|
#Line # saves Clip and Matrix on stack; creates Layer; sets opacity ##
|
|
#Populate
|
|
|
|
#Example
|
|
SkPaint paint;
|
|
paint.setColor(SK_ColorRED);
|
|
canvas->drawCircle(50, 50, 50, paint);
|
|
canvas->saveLayerAlpha(nullptr, 128);
|
|
paint.setColor(SK_ColorBLUE);
|
|
canvas->drawCircle(100, 50, 50, paint);
|
|
paint.setColor(SK_ColorGREEN);
|
|
paint.setAlpha(128);
|
|
canvas->drawCircle(75, 90, 50, paint);
|
|
canvas->restore();
|
|
##
|
|
|
|
#SeeAlso save restore saveLayer saveLayerPreserveLCDTextRequests SaveLayerRec
|
|
|
|
##
|
|
|
|
#Enum SaveLayerFlagsSet
|
|
#Line # sets SaveLayerRec options ##
|
|
#Code
|
|
#Populate
|
|
##
|
|
|
|
|
|
#Typedef uint32_t SaveLayerFlags
|
|
#Line # options for SaveLayerRec ##
|
|
##
|
|
|
|
SaveLayerFlags provides options that may be used in any combination in SaveLayerRec,
|
|
defining how Layer allocated by saveLayer operates. It may be set to zero,
|
|
kPreserveLCDText_SaveLayerFlag, kInitWithPrevious_SaveLayerFlag, or both flags.
|
|
|
|
#Const kPreserveLCDText_SaveLayerFlag 2
|
|
#Line # creates Layer for LCD text ##
|
|
Creates Layer for LCD text. Flag is ignored if Layer Paint contains
|
|
Image_Filter or Color_Filter.
|
|
##
|
|
|
|
#Const kInitWithPrevious_SaveLayerFlag 4
|
|
#Line # initializes with previous contents ##
|
|
Initializes Layer with the contents of the previous Layer.
|
|
##
|
|
|
|
#Example
|
|
#Height 160
|
|
#Description
|
|
Canvas Layer captures red and blue circles scaled up by four.
|
|
scalePaint blends Layer back with transparency.
|
|
##
|
|
void draw(SkCanvas* canvas) {
|
|
SkPaint redPaint, bluePaint, scalePaint;
|
|
redPaint.setColor(SK_ColorRED);
|
|
canvas->drawCircle(21, 21, 8, redPaint);
|
|
bluePaint.setColor(SK_ColorBLUE);
|
|
canvas->drawCircle(31, 21, 8, bluePaint);
|
|
SkMatrix matrix;
|
|
matrix.setScale(4, 4);
|
|
scalePaint.setAlpha(0x40);
|
|
scalePaint.setImageFilter(
|
|
SkImageFilter::MakeMatrixFilter(matrix, kNone_SkFilterQuality, nullptr));
|
|
SkCanvas::SaveLayerRec saveLayerRec(nullptr, &scalePaint,
|
|
SkCanvas::kInitWithPrevious_SaveLayerFlag);
|
|
canvas->saveLayer(saveLayerRec);
|
|
canvas->restore();
|
|
}
|
|
##
|
|
|
|
#SeeAlso save restore saveLayer saveLayerPreserveLCDTextRequests saveLayerAlpha SaveLayerRec
|
|
|
|
#Enum ##
|
|
|
|
#Subtopic SaveLayerRec
|
|
#Line # contains the state used to create the Layer ##
|
|
|
|
#Struct SaveLayerRec
|
|
#Line # contains the state used to create the Layer ##
|
|
|
|
#Code
|
|
#Populate
|
|
##
|
|
|
|
SaveLayerRec contains the state used to create the Layer.
|
|
|
|
#Member const SkRect* fBounds
|
|
#Line # hints at Layer size limit ##
|
|
fBounds is used as a hint to limit the size of Layer; may be nullptr.
|
|
fBounds suggests but does not define Layer size. To clip drawing to
|
|
a specific rectangle, use clipRect.
|
|
##
|
|
|
|
#Member const SkPaint* fPaint
|
|
#Line # modifies overlay ##
|
|
fPaint modifies how Layer overlays the prior Layer; may be nullptr.
|
|
Color_Alpha, Blend_Mode, Color_Filter, Draw_Looper, Image_Filter, and
|
|
Mask_Filter affect Layer draw.
|
|
##
|
|
|
|
#Member const SkImageFilter* fBackdrop
|
|
#Line # applies Image_Filter to prior Layer ##
|
|
fBackdrop applies Image_Filter to the prior Layer when copying to the Layer;
|
|
may be nullptr. Use kInitWithPrevious_SaveLayerFlag to copy the
|
|
prior Layer without an Image_Filter.
|
|
##
|
|
|
|
#Member const SkImage* fClipMask
|
|
#Line # clips Layer with Mask_Alpha ##
|
|
restore() clips Layer by the Color_Alpha channel of fClipMask when
|
|
Layer is copied to Device. fClipMask may be nullptr. .
|
|
##
|
|
|
|
#Member const SkMatrix* fClipMatrix
|
|
#Line # transforms Mask_Alpha used to clip ##
|
|
fClipMatrix transforms fClipMask before it clips Layer. If
|
|
fClipMask describes a translucent gradient, it may be scaled and rotated
|
|
without introducing artifacts. fClipMatrix may be nullptr.
|
|
##
|
|
|
|
#Member SaveLayerFlags fSaveLayerFlags
|
|
#Line # preserves LCD Text, creates with prior Layer contents ##
|
|
fSaveLayerFlags are used to create Layer without transparency,
|
|
create Layer for LCD text, and to create Layer with the
|
|
contents of the previous Layer.
|
|
##
|
|
|
|
#Example
|
|
#Height 160
|
|
#Description
|
|
Canvas Layer captures a red Anti_Aliased circle and a blue Aliased circle scaled
|
|
up by four. After drawing another red circle without scaling on top, the Layer is
|
|
transferred to the main canvas.
|
|
##
|
|
void draw(SkCanvas* canvas) {
|
|
SkPaint redPaint, bluePaint;
|
|
redPaint.setAntiAlias(true);
|
|
redPaint.setColor(SK_ColorRED);
|
|
canvas->drawCircle(21, 21, 8, redPaint);
|
|
bluePaint.setColor(SK_ColorBLUE);
|
|
canvas->drawCircle(31, 21, 8, bluePaint);
|
|
SkMatrix matrix;
|
|
matrix.setScale(4, 4);
|
|
auto scaler = SkImageFilter::MakeMatrixFilter(matrix, kNone_SkFilterQuality, nullptr);
|
|
SkCanvas::SaveLayerRec saveLayerRec(nullptr, nullptr, scaler.get(), 0);
|
|
canvas->saveLayer(saveLayerRec);
|
|
canvas->drawCircle(125, 85, 8, redPaint);
|
|
canvas->restore();
|
|
}
|
|
##
|
|
|
|
#Subtopic Constructors
|
|
##
|
|
|
|
#Method SaveLayerRec()
|
|
#Line # constructs SaveLayerRec ##
|
|
#Populate
|
|
|
|
#Example
|
|
SkCanvas::SaveLayerRec rec1;
|
|
rec1.fSaveLayerFlags = SkCanvas::kPreserveLCDText_SaveLayerFlag;
|
|
SkCanvas::SaveLayerRec rec2(nullptr, nullptr, SkCanvas::kPreserveLCDText_SaveLayerFlag);
|
|
SkDebugf("rec1 %c= rec2\n", rec1.fBounds == rec2.fBounds
|
|
&& rec1.fPaint == rec2.fPaint
|
|
&& rec1.fBackdrop == rec2.fBackdrop
|
|
&& rec1.fSaveLayerFlags == rec2.fSaveLayerFlags ? '=' : '!');
|
|
#StdOut
|
|
rec1 == rec2
|
|
##
|
|
##
|
|
|
|
#SeeAlso save restore saveLayer saveLayerPreserveLCDTextRequests saveLayerAlpha
|
|
|
|
##
|
|
|
|
#Method SaveLayerRec(const SkRect* bounds, const SkPaint* paint, SaveLayerFlags saveLayerFlags = 0)
|
|
#Populate
|
|
|
|
#Example
|
|
SkCanvas::SaveLayerRec rec1;
|
|
SkCanvas::SaveLayerRec rec2(nullptr, nullptr);
|
|
SkDebugf("rec1 %c= rec2\n", rec1.fBounds == rec2.fBounds
|
|
&& rec1.fPaint == rec2.fPaint
|
|
&& rec1.fBackdrop == rec2.fBackdrop
|
|
&& rec1.fSaveLayerFlags == rec2.fSaveLayerFlags ? '=' : '!');
|
|
#StdOut
|
|
rec1 == rec2
|
|
##
|
|
##
|
|
|
|
#SeeAlso save restore saveLayer saveLayerPreserveLCDTextRequests saveLayerAlpha
|
|
|
|
##
|
|
|
|
#Method SaveLayerRec(const SkRect* bounds, const SkPaint* paint, const SkImageFilter* backdrop,
|
|
SaveLayerFlags saveLayerFlags)
|
|
#Populate
|
|
|
|
#Example
|
|
SkCanvas::SaveLayerRec rec1;
|
|
SkCanvas::SaveLayerRec rec2(nullptr, nullptr, nullptr, 0);
|
|
SkDebugf("rec1 %c= rec2\n", rec1.fBounds == rec2.fBounds
|
|
&& rec1.fPaint == rec2.fPaint
|
|
&& rec1.fBackdrop == rec2.fBackdrop
|
|
&& rec1.fSaveLayerFlags == rec2.fSaveLayerFlags ? '=' : '!');
|
|
#StdOut
|
|
rec1 == rec2
|
|
##
|
|
##
|
|
|
|
#SeeAlso save restore saveLayer saveLayerPreserveLCDTextRequests saveLayerAlpha
|
|
|
|
##
|
|
|
|
#Struct ##
|
|
|
|
#Subtopic ##
|
|
|
|
#Method int saveLayer(const SaveLayerRec& layerRec)
|
|
|
|
#In Layer
|
|
#Populate
|
|
|
|
#Example
|
|
#Description
|
|
The example draws an image, and saves it into a Layer with kInitWithPrevious_SaveLayerFlag.
|
|
Next it punches a hole in Layer and restore with SkBlendMode::kPlus.
|
|
Where Layer was cleared, the original image will draw unchanged.
|
|
Outside of the circle the mandrill is brightened.
|
|
##
|
|
#Image 3
|
|
// sk_sp<SkImage> image = GetResourceAsImage("images/mandrill_256.png");
|
|
canvas->drawImage(image, 0, 0, nullptr);
|
|
SkCanvas::SaveLayerRec rec;
|
|
SkPaint paint;
|
|
paint.setBlendMode(SkBlendMode::kPlus);
|
|
rec.fSaveLayerFlags = SkCanvas::kInitWithPrevious_SaveLayerFlag;
|
|
rec.fPaint = &paint;
|
|
canvas->saveLayer(rec);
|
|
paint.setBlendMode(SkBlendMode::kClear);
|
|
canvas->drawCircle(128, 128, 96, paint);
|
|
canvas->restore();
|
|
##
|
|
|
|
#ToDo above example needs to replace GetResourceAsImage with way to select image in fiddle ##
|
|
|
|
#SeeAlso save restore saveLayer saveLayerPreserveLCDTextRequests saveLayerAlpha
|
|
|
|
##
|
|
|
|
#Subtopic Layer ##
|
|
|
|
# ------------------------------------------------------------------------------
|
|
#Subtopic Matrix
|
|
#Line # coordinate transformation ##
|
|
|
|
#Method void translate(SkScalar dx, SkScalar dy)
|
|
|
|
#In Matrix
|
|
#Line # translates Matrix ##
|
|
#Populate
|
|
|
|
#Example
|
|
#Height 128
|
|
#Description
|
|
scale() followed by translate() produces different results from translate() followed
|
|
by scale().
|
|
|
|
The blue stroke follows translate of (50, 50); a black
|
|
fill follows scale of (2, 1/2.f). After restoring the clip, which resets
|
|
Matrix, a red frame follows the same scale of (2, 1/2.f); a gray fill
|
|
follows translate of (50, 50).
|
|
##
|
|
void draw(SkCanvas* canvas) {
|
|
SkPaint filledPaint;
|
|
SkPaint outlinePaint;
|
|
outlinePaint.setStyle(SkPaint::kStroke_Style);
|
|
outlinePaint.setColor(SK_ColorBLUE);
|
|
canvas->save();
|
|
canvas->translate(50, 50);
|
|
canvas->drawCircle(28, 28, 15, outlinePaint); // blue center: (50+28, 50+28)
|
|
canvas->scale(2, 1/2.f);
|
|
canvas->drawCircle(28, 28, 15, filledPaint); // black center: (50+(28*2), 50+(28/2))
|
|
canvas->restore();
|
|
filledPaint.setColor(SK_ColorGRAY);
|
|
outlinePaint.setColor(SK_ColorRED);
|
|
canvas->scale(2, 1/2.f);
|
|
canvas->drawCircle(28, 28, 15, outlinePaint); // red center: (28*2, 28/2)
|
|
canvas->translate(50, 50);
|
|
canvas->drawCircle(28, 28, 15, filledPaint); // gray center: ((50+28)*2, (50+28)/2)
|
|
}
|
|
##
|
|
|
|
#SeeAlso concat() scale() skew() rotate() setMatrix
|
|
|
|
##
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
#Method void scale(SkScalar sx, SkScalar sy)
|
|
|
|
#In Matrix
|
|
#Line # scales Matrix ##
|
|
#Populate
|
|
|
|
#Example
|
|
#Height 160
|
|
void draw(SkCanvas* canvas) {
|
|
SkPaint paint;
|
|
SkRect rect = { 10, 20, 60, 120 };
|
|
canvas->translate(20, 20);
|
|
canvas->drawRect(rect, paint);
|
|
canvas->scale(2, .5f);
|
|
paint.setColor(SK_ColorGRAY);
|
|
canvas->drawRect(rect, paint);
|
|
}
|
|
##
|
|
|
|
#SeeAlso concat() translate() skew() rotate() setMatrix
|
|
|
|
##
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
#Method void rotate(SkScalar degrees)
|
|
|
|
#In Matrix
|
|
#Line # rotates Matrix ##
|
|
#Populate
|
|
|
|
#Example
|
|
#Description
|
|
Draw clock hands at time 5:10. The hour hand and minute hand point up and
|
|
are rotated clockwise.
|
|
##
|
|
void draw(SkCanvas* canvas) {
|
|
SkPaint paint;
|
|
paint.setStyle(SkPaint::kStroke_Style);
|
|
canvas->translate(128, 128);
|
|
canvas->drawCircle(0, 0, 60, paint);
|
|
canvas->save();
|
|
canvas->rotate(10 * 360 / 60); // 10 minutes of 60 scaled to 360 degrees
|
|
canvas->drawLine(0, 0, 0, -50, paint);
|
|
canvas->restore();
|
|
canvas->rotate((5 + 10.f/60) * 360 / 12); // 5 and 10/60 hours of 12 scaled to 360 degrees
|
|
canvas->drawLine(0, 0, 0, -30, paint);
|
|
}
|
|
##
|
|
|
|
#SeeAlso concat() translate() skew() scale() setMatrix
|
|
|
|
##
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
#Method void rotate(SkScalar degrees, SkScalar px, SkScalar py)
|
|
|
|
#In Matrix
|
|
#Populate
|
|
|
|
#Example
|
|
#Height 192
|
|
void draw(SkCanvas* canvas) {
|
|
SkPaint paint;
|
|
paint.setTextSize(96);
|
|
canvas->drawString("A1", 130, 100, paint);
|
|
canvas->rotate(180, 130, 100);
|
|
canvas->drawString("A1", 130, 100, paint);
|
|
}
|
|
##
|
|
|
|
#SeeAlso concat() translate() skew() scale() setMatrix
|
|
|
|
##
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
#Method void skew(SkScalar sx, SkScalar sy)
|
|
|
|
#In Matrix
|
|
#Line # skews Matrix ##
|
|
#Populate
|
|
|
|
#Example
|
|
#Description
|
|
Black text mimics an oblique text style by using a negative skew on x-axis
|
|
that shifts the geometry to the right as the y-axis values decrease.
|
|
Red text uses a positive skew on y-axis to shift the geometry down
|
|
as the x-axis values increase.
|
|
Blue text combines sx and sy skew to rotate and scale.
|
|
##
|
|
SkPaint paint;
|
|
paint.setTextSize(128);
|
|
canvas->translate(30, 130);
|
|
canvas->save();
|
|
canvas->skew(-.5, 0);
|
|
canvas->drawString("A1", 0, 0, paint);
|
|
canvas->restore();
|
|
canvas->save();
|
|
canvas->skew(0, .5);
|
|
paint.setColor(SK_ColorRED);
|
|
canvas->drawString("A1", 0, 0, paint);
|
|
canvas->restore();
|
|
canvas->skew(-.5, .5);
|
|
paint.setColor(SK_ColorBLUE);
|
|
canvas->drawString("A1", 0, 0, paint);
|
|
##
|
|
|
|
#SeeAlso concat() translate() rotate() scale() setMatrix
|
|
|
|
##
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
#Method void concat(const SkMatrix& matrix)
|
|
|
|
#In Matrix
|
|
#Line # multiplies Matrix by Matrix ##
|
|
#Populate
|
|
|
|
#Example
|
|
void draw(SkCanvas* canvas) {
|
|
SkPaint paint;
|
|
paint.setTextSize(80);
|
|
paint.setTextScaleX(.3);
|
|
SkMatrix matrix;
|
|
SkRect rect[2] = {{ 10, 20, 90, 110 }, { 40, 130, 140, 180 }};
|
|
matrix.setRectToRect(rect[0], rect[1], SkMatrix::kFill_ScaleToFit);
|
|
canvas->drawRect(rect[0], paint);
|
|
canvas->drawRect(rect[1], paint);
|
|
paint.setColor(SK_ColorWHITE);
|
|
canvas->drawString("Here", rect[0].fLeft + 10, rect[0].fBottom - 10, paint);
|
|
canvas->concat(matrix);
|
|
canvas->drawString("There", rect[0].fLeft + 10, rect[0].fBottom - 10, paint);
|
|
}
|
|
##
|
|
|
|
#SeeAlso translate() rotate() scale() skew() setMatrix
|
|
|
|
##
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
#Method void setMatrix(const SkMatrix& matrix)
|
|
|
|
#In Matrix
|
|
#Line # sets Matrix ##
|
|
#Populate
|
|
|
|
#Example
|
|
#Height 128
|
|
void draw(SkCanvas* canvas) {
|
|
SkPaint paint;
|
|
canvas->scale(4, 6);
|
|
canvas->drawString("truth", 2, 10, paint);
|
|
SkMatrix matrix;
|
|
matrix.setScale(2.8f, 6);
|
|
canvas->setMatrix(matrix);
|
|
canvas->drawString("consequences", 2, 20, paint);
|
|
}
|
|
##
|
|
|
|
#SeeAlso resetMatrix concat() translate() rotate() scale() skew()
|
|
|
|
##
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
#Method void resetMatrix()
|
|
|
|
#In Matrix
|
|
#Line # resets Matrix to identity ##
|
|
#Populate
|
|
|
|
#Example
|
|
#Height 128
|
|
void draw(SkCanvas* canvas) {
|
|
SkPaint paint;
|
|
canvas->scale(4, 6);
|
|
canvas->drawString("truth", 2, 10, paint);
|
|
canvas->resetMatrix();
|
|
canvas->scale(2.8f, 6);
|
|
canvas->drawString("consequences", 2, 20, paint);
|
|
}
|
|
##
|
|
|
|
#SeeAlso setMatrix concat() translate() rotate() scale() skew()
|
|
|
|
##
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
#Method const SkMatrix& getTotalMatrix() const
|
|
|
|
#In Matrix
|
|
#Line # returns Matrix ##
|
|
#Populate
|
|
|
|
#Example
|
|
SkDebugf("isIdentity %s\n", canvas->getTotalMatrix().isIdentity() ? "true" : "false");
|
|
#StdOut
|
|
isIdentity true
|
|
##
|
|
##
|
|
|
|
#SeeAlso setMatrix resetMatrix concat()
|
|
|
|
##
|
|
|
|
#Subtopic Matrix ##
|
|
|
|
# ------------------------------------------------------------------------------
|
|
#Subtopic Clip
|
|
#Line # stack of clipping Paths ##
|
|
|
|
Clip is built from a stack of clipping paths. Each Path in the
|
|
stack can be constructed from one or more Path_Contour elements. The
|
|
Path_Contour may be composed of any number of Path_Verb segments. Each
|
|
Path_Contour forms a closed area; Path_Fill_Type defines the area enclosed
|
|
by Path_Contour.
|
|
|
|
Clip stack of Path elements successfully restrict the Path area. Each
|
|
Path is transformed by Matrix, then intersected with or subtracted from the
|
|
prior Clip to form the replacement Clip. Use SkClipOp::kDifference
|
|
to subtract Path from Clip; use SkClipOp::kIntersect to intersect Path
|
|
with Clip.
|
|
|
|
A clipping Path may be Anti_Aliased; if Path, after transformation, is
|
|
composed of horizontal and vertical lines, clearing Anti_Alias allows whole pixels
|
|
to either be inside or outside the clip. The fastest drawing has a Aliased,
|
|
rectangular clip.
|
|
|
|
If clipping Path has Anti_Alias set, clip may partially clip a pixel, requiring
|
|
that drawing blend partially with the destination along the edge. A rotated
|
|
rectangular Anti_Aliased clip looks smoother but draws slower.
|
|
|
|
Clip can combine with Rect and Round_Rect primitives; like
|
|
Path, these are transformed by Matrix before they are combined with Clip.
|
|
|
|
Clip can combine with Region. Region is assumed to be in Device coordinates
|
|
and is unaffected by Matrix.
|
|
|
|
#Example
|
|
#Height 90
|
|
#Description
|
|
Draw a red circle with an Aliased clip and an Anti_Aliased clip.
|
|
Use an image filter to zoom into the pixels drawn.
|
|
The edge of the Aliased clip fully draws pixels in the red circle.
|
|
The edge of the Anti_Aliased clip partially draws pixels in the red circle.
|
|
##
|
|
SkPaint redPaint, scalePaint;
|
|
redPaint.setAntiAlias(true);
|
|
redPaint.setColor(SK_ColorRED);
|
|
canvas->save();
|
|
for (bool antialias : { false, true } ) {
|
|
canvas->save();
|
|
canvas->clipRect(SkRect::MakeWH(19.5f, 11.5f), antialias);
|
|
canvas->drawCircle(17, 11, 8, redPaint);
|
|
canvas->restore();
|
|
canvas->translate(16, 0);
|
|
}
|
|
canvas->restore();
|
|
SkMatrix matrix;
|
|
matrix.setScale(6, 6);
|
|
scalePaint.setImageFilter(
|
|
SkImageFilter::MakeMatrixFilter(matrix, kNone_SkFilterQuality, nullptr));
|
|
SkCanvas::SaveLayerRec saveLayerRec(
|
|
nullptr, &scalePaint, SkCanvas::kInitWithPrevious_SaveLayerFlag);
|
|
canvas->saveLayer(saveLayerRec);
|
|
canvas->restore();
|
|
##
|
|
|
|
#Method void clipRect(const SkRect& rect, SkClipOp op, bool doAntiAlias)
|
|
|
|
#In Clip
|
|
#Line # combines Clip with Rect ##
|
|
#Populate
|
|
|
|
#Example
|
|
#Height 128
|
|
void draw(SkCanvas* canvas) {
|
|
canvas->rotate(10);
|
|
SkPaint paint;
|
|
paint.setAntiAlias(true);
|
|
for (auto alias: { false, true } ) {
|
|
canvas->save();
|
|
canvas->clipRect(SkRect::MakeWH(90, 80), SkClipOp::kIntersect, alias);
|
|
canvas->drawCircle(100, 60, 60, paint);
|
|
canvas->restore();
|
|
canvas->translate(80, 0);
|
|
}
|
|
}
|
|
##
|
|
|
|
#SeeAlso clipRRect clipPath clipRegion
|
|
|
|
##
|
|
|
|
#Method void clipRect(const SkRect& rect, SkClipOp op)
|
|
|
|
#In Clip
|
|
#Populate
|
|
|
|
#Example
|
|
#Height 192
|
|
#Width 280
|
|
void draw(SkCanvas* canvas) {
|
|
SkPaint paint;
|
|
for (SkClipOp op: { SkClipOp::kIntersect, SkClipOp::kDifference } ) {
|
|
canvas->save();
|
|
canvas->clipRect(SkRect::MakeWH(90, 120), op, false);
|
|
canvas->drawCircle(100, 100, 60, paint);
|
|
canvas->restore();
|
|
canvas->translate(80, 0);
|
|
}
|
|
}
|
|
##
|
|
|
|
#SeeAlso clipRRect clipPath clipRegion
|
|
|
|
##
|
|
|
|
#Method void clipRect(const SkRect& rect, bool doAntiAlias = false)
|
|
|
|
#In Clip
|
|
#Populate
|
|
|
|
#Example
|
|
#Height 133
|
|
#Description
|
|
A circle drawn in pieces looks uniform when drawn Aliased.
|
|
The same circle pieces blend with pixels more than once when Anti_Aliased,
|
|
visible as a thin pair of lines through the right circle.
|
|
##
|
|
void draw(SkCanvas* canvas) {
|
|
canvas->clear(SK_ColorWHITE);
|
|
SkPaint paint;
|
|
paint.setAntiAlias(true);
|
|
paint.setColor(0x8055aaff);
|
|
SkRect clipRect = { 0, 0, 87.4f, 87.4f };
|
|
for (auto alias: { false, true } ) {
|
|
canvas->save();
|
|
canvas->clipRect(clipRect, SkClipOp::kIntersect, alias);
|
|
canvas->drawCircle(67, 67, 60, paint);
|
|
canvas->restore();
|
|
canvas->save();
|
|
canvas->clipRect(clipRect, SkClipOp::kDifference, alias);
|
|
canvas->drawCircle(67, 67, 60, paint);
|
|
canvas->restore();
|
|
canvas->translate(120, 0);
|
|
}
|
|
}
|
|
##
|
|
|
|
#SeeAlso clipRRect clipPath clipRegion
|
|
|
|
##
|
|
|
|
#Method void clipRRect(const SkRRect& rrect, SkClipOp op, bool doAntiAlias)
|
|
|
|
#In Clip
|
|
#Line # combines Clip with Round_Rect ##
|
|
#Populate
|
|
|
|
#Example
|
|
#Height 128
|
|
void draw(SkCanvas* canvas) {
|
|
canvas->clear(SK_ColorWHITE);
|
|
SkPaint paint;
|
|
paint.setAntiAlias(true);
|
|
paint.setColor(0x8055aaff);
|
|
SkRRect oval;
|
|
oval.setOval({10, 20, 90, 100});
|
|
canvas->clipRRect(oval, SkClipOp::kIntersect, true);
|
|
canvas->drawCircle(70, 100, 60, paint);
|
|
}
|
|
##
|
|
|
|
#SeeAlso clipRect clipPath clipRegion
|
|
|
|
##
|
|
|
|
#Method void clipRRect(const SkRRect& rrect, SkClipOp op)
|
|
|
|
#In Clip
|
|
#Populate
|
|
|
|
#Example
|
|
#Height 128
|
|
void draw(SkCanvas* canvas) {
|
|
SkPaint paint;
|
|
paint.setColor(0x8055aaff);
|
|
auto oval = SkRRect::MakeOval({10, 20, 90, 100});
|
|
canvas->clipRRect(oval, SkClipOp::kIntersect);
|
|
canvas->drawCircle(70, 100, 60, paint);
|
|
}
|
|
##
|
|
|
|
#SeeAlso clipRect clipPath clipRegion
|
|
|
|
##
|
|
|
|
#Method void clipRRect(const SkRRect& rrect, bool doAntiAlias = false)
|
|
|
|
#In Clip
|
|
#Populate
|
|
|
|
#Example
|
|
#Height 128
|
|
void draw(SkCanvas* canvas) {
|
|
SkPaint paint;
|
|
paint.setAntiAlias(true);
|
|
auto oval = SkRRect::MakeRectXY({10, 20, 90, 100}, 9, 13);
|
|
canvas->clipRRect(oval, true);
|
|
canvas->drawCircle(70, 100, 60, paint);
|
|
}
|
|
##
|
|
|
|
#SeeAlso clipRect clipPath clipRegion
|
|
|
|
##
|
|
|
|
#Method void clipPath(const SkPath& path, SkClipOp op, bool doAntiAlias)
|
|
|
|
#In Clip
|
|
#Line # combines Clip with Path ##
|
|
#Populate
|
|
|
|
#Example
|
|
#Description
|
|
Top figure uses SkPath::kInverseWinding_FillType and SkClipOp::kDifference;
|
|
area outside clip is subtracted from circle.
|
|
|
|
Bottom figure uses SkPath::kWinding_FillType and SkClipOp::kIntersect;
|
|
area inside clip is intersected with circle.
|
|
##
|
|
void draw(SkCanvas* canvas) {
|
|
SkPaint paint;
|
|
paint.setAntiAlias(true);
|
|
SkPath path;
|
|
path.addRect({20, 30, 100, 110});
|
|
path.setFillType(SkPath::kInverseWinding_FillType);
|
|
canvas->save();
|
|
canvas->clipPath(path, SkClipOp::kDifference, false);
|
|
canvas->drawCircle(70, 100, 60, paint);
|
|
canvas->restore();
|
|
canvas->translate(100, 100);
|
|
path.setFillType(SkPath::kWinding_FillType);
|
|
canvas->clipPath(path, SkClipOp::kIntersect, false);
|
|
canvas->drawCircle(70, 100, 60, paint);
|
|
}
|
|
##
|
|
|
|
#SeeAlso clipRect clipRRect clipRegion
|
|
|
|
##
|
|
|
|
#Method void clipPath(const SkPath& path, SkClipOp op)
|
|
|
|
#In Clip
|
|
#Populate
|
|
|
|
#Example
|
|
#Description
|
|
Overlapping Rects form a clip. When clip Path_Fill_Type is set to
|
|
SkPath::kWinding_FillType, the overlap is included. Set to
|
|
SkPath::kEvenOdd_FillType, the overlap is excluded and forms a hole.
|
|
##
|
|
void draw(SkCanvas* canvas) {
|
|
SkPaint paint;
|
|
paint.setAntiAlias(true);
|
|
SkPath path;
|
|
path.addRect({20, 15, 100, 95});
|
|
path.addRect({50, 65, 130, 135});
|
|
path.setFillType(SkPath::kWinding_FillType);
|
|
canvas->save();
|
|
canvas->clipPath(path, SkClipOp::kIntersect);
|
|
canvas->drawCircle(70, 85, 60, paint);
|
|
canvas->restore();
|
|
canvas->translate(100, 100);
|
|
path.setFillType(SkPath::kEvenOdd_FillType);
|
|
canvas->clipPath(path, SkClipOp::kIntersect);
|
|
canvas->drawCircle(70, 85, 60, paint);
|
|
}
|
|
##
|
|
|
|
#SeeAlso clipRect clipRRect clipRegion
|
|
|
|
##
|
|
|
|
#Method void clipPath(const SkPath& path, bool doAntiAlias = false)
|
|
|
|
#In Clip
|
|
#Populate
|
|
|
|
#Example
|
|
#Height 212
|
|
#Description
|
|
Clip loops over itself covering its center twice. When clip Path_Fill_Type
|
|
is set to SkPath::kWinding_FillType, the overlap is included. Set to
|
|
SkPath::kEvenOdd_FillType, the overlap is excluded and forms a hole.
|
|
##
|
|
void draw(SkCanvas* canvas) {
|
|
SkPaint paint;
|
|
paint.setAntiAlias(true);
|
|
SkPath path;
|
|
SkPoint poly[] = {{20, 20}, { 80, 20}, { 80, 80}, {40, 80},
|
|
{40, 40}, {100, 40}, {100, 100}, {20, 100}};
|
|
path.addPoly(poly, SK_ARRAY_COUNT(poly), true);
|
|
path.setFillType(SkPath::kWinding_FillType);
|
|
canvas->save();
|
|
canvas->clipPath(path, SkClipOp::kIntersect);
|
|
canvas->drawCircle(50, 50, 45, paint);
|
|
canvas->restore();
|
|
canvas->translate(100, 100);
|
|
path.setFillType(SkPath::kEvenOdd_FillType);
|
|
canvas->clipPath(path, SkClipOp::kIntersect);
|
|
canvas->drawCircle(50, 50, 45, paint);
|
|
}
|
|
##
|
|
|
|
#SeeAlso clipRect clipRRect clipRegion
|
|
|
|
##
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
#Method void clipRegion(const SkRegion& deviceRgn, SkClipOp op = SkClipOp::kIntersect)
|
|
|
|
#In Clip
|
|
#Line # combines Clip with Region ##
|
|
#Populate
|
|
|
|
#Example
|
|
#Description
|
|
region is unaffected by canvas rotation; iRect is affected by canvas rotation.
|
|
Both clips are Aliased; this is not noticeable on Region clip because it
|
|
aligns to pixel boundaries.
|
|
##
|
|
void draw(SkCanvas* canvas) {
|
|
SkPaint paint;
|
|
paint.setAntiAlias(true);
|
|
SkIRect iRect = {30, 40, 120, 130 };
|
|
SkRegion region(iRect);
|
|
canvas->rotate(10);
|
|
canvas->save();
|
|
canvas->clipRegion(region, SkClipOp::kIntersect);
|
|
canvas->drawCircle(50, 50, 45, paint);
|
|
canvas->restore();
|
|
canvas->translate(100, 100);
|
|
canvas->clipRect(SkRect::Make(iRect), SkClipOp::kIntersect);
|
|
canvas->drawCircle(50, 50, 45, paint);
|
|
}
|
|
##
|
|
|
|
#SeeAlso clipRect clipRRect clipPath
|
|
|
|
##
|
|
|
|
#Method bool quickReject(const SkRect& rect) const
|
|
|
|
#In Clip
|
|
#Line # returns if Rect is outside Clip ##
|
|
#Populate
|
|
|
|
#Example
|
|
void draw(SkCanvas* canvas) {
|
|
SkRect testRect = {30, 30, 120, 129 };
|
|
SkRect clipRect = {30, 130, 120, 230 };
|
|
canvas->save();
|
|
canvas->clipRect(clipRect);
|
|
SkDebugf("quickReject %s\n", canvas->quickReject(testRect) ? "true" : "false");
|
|
canvas->restore();
|
|
canvas->rotate(10);
|
|
canvas->clipRect(clipRect);
|
|
SkDebugf("quickReject %s\n", canvas->quickReject(testRect) ? "true" : "false");
|
|
}
|
|
#StdOut
|
|
quickReject true
|
|
quickReject false
|
|
##
|
|
##
|
|
|
|
#SeeAlso getLocalClipBounds getTotalMatrix SkBitmap::drawsNothing
|
|
|
|
##
|
|
|
|
#Method bool quickReject(const SkPath& path) const
|
|
|
|
#In Clip
|
|
#Populate
|
|
|
|
#Example
|
|
void draw(SkCanvas* canvas) {
|
|
SkPoint testPoints[] = {{30, 30}, {120, 30}, {120, 129} };
|
|
SkPoint clipPoints[] = {{30, 130}, {120, 130}, {120, 230} };
|
|
SkPath testPath, clipPath;
|
|
testPath.addPoly(testPoints, SK_ARRAY_COUNT(testPoints), true);
|
|
clipPath.addPoly(clipPoints, SK_ARRAY_COUNT(clipPoints), true);
|
|
canvas->save();
|
|
canvas->clipPath(clipPath);
|
|
SkDebugf("quickReject %s\n", canvas->quickReject(testPath) ? "true" : "false");
|
|
canvas->restore();
|
|
canvas->rotate(10);
|
|
canvas->clipPath(clipPath);
|
|
SkDebugf("quickReject %s\n", canvas->quickReject(testPath) ? "true" : "false");
|
|
#StdOut
|
|
quickReject true
|
|
quickReject false
|
|
##
|
|
}
|
|
##
|
|
|
|
#SeeAlso getLocalClipBounds getTotalMatrix SkBitmap::drawsNothing
|
|
|
|
##
|
|
|
|
#Method SkRect getLocalClipBounds() const
|
|
|
|
#In Clip
|
|
#Line # returns Clip bounds in source coordinates ##
|
|
#Populate
|
|
|
|
#Example
|
|
#Description
|
|
Initial bounds is device bounds outset by 1 on all sides.
|
|
Clipped bounds is clipPath bounds outset by 1 on all sides.
|
|
Scaling the canvas by two on both axes scales the local bounds by 1/2
|
|
on both axes.
|
|
##
|
|
SkCanvas local(256, 256);
|
|
canvas = &local;
|
|
SkRect bounds = canvas->getLocalClipBounds();
|
|
SkDebugf("left:%g top:%g right:%g bottom:%g\n",
|
|
bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom);
|
|
SkPoint clipPoints[] = {{30, 130}, {120, 130}, {120, 230} };
|
|
SkPath clipPath;
|
|
clipPath.addPoly(clipPoints, SK_ARRAY_COUNT(clipPoints), true);
|
|
canvas->clipPath(clipPath);
|
|
bounds = canvas->getLocalClipBounds();
|
|
SkDebugf("left:%g top:%g right:%g bottom:%g\n",
|
|
bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom);
|
|
canvas->scale(2, 2);
|
|
bounds = canvas->getLocalClipBounds();
|
|
SkDebugf("left:%g top:%g right:%g bottom:%g\n",
|
|
bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom);
|
|
#StdOut
|
|
left:-1 top:-1 right:257 bottom:257
|
|
left:29 top:129 right:121 bottom:231
|
|
left:14.5 top:64.5 right:60.5 bottom:115.5
|
|
##
|
|
##
|
|
|
|
# local canvas in example works around bug in fiddle ##
|
|
#Bug 6524
|
|
#SeeAlso getDeviceClipBounds getBaseLayerSize quickReject
|
|
|
|
##
|
|
|
|
#Method bool getLocalClipBounds(SkRect* bounds) const
|
|
|
|
#In Clip
|
|
#Populate
|
|
|
|
#Example
|
|
void draw(SkCanvas* canvas) {
|
|
SkCanvas local(256, 256);
|
|
canvas = &local;
|
|
SkRect bounds;
|
|
SkDebugf("local bounds empty = %s\n", canvas->getLocalClipBounds(&bounds)
|
|
? "false" : "true");
|
|
SkPath path;
|
|
canvas->clipPath(path);
|
|
SkDebugf("local bounds empty = %s\n", canvas->getLocalClipBounds(&bounds)
|
|
? "false" : "true");
|
|
}
|
|
#StdOut
|
|
local bounds empty = false
|
|
local bounds empty = true
|
|
##
|
|
##
|
|
|
|
# local canvas in example works around bug in fiddle ##
|
|
#Bug 6524
|
|
#SeeAlso getDeviceClipBounds getBaseLayerSize quickReject
|
|
|
|
##
|
|
|
|
#Method SkIRect getDeviceClipBounds() const
|
|
|
|
#In Clip
|
|
#Line # returns IRect bounds of Clip ##
|
|
#Populate
|
|
|
|
#Example
|
|
void draw(SkCanvas* canvas) {
|
|
#Description
|
|
Initial bounds is device bounds, not outset.
|
|
Clipped bounds is clipPath bounds, not outset.
|
|
Scaling the canvas by 1/2 on both axes scales the device bounds by 1/2
|
|
on both axes.
|
|
##
|
|
SkCanvas device(256, 256);
|
|
canvas = &device;
|
|
SkIRect bounds = canvas->getDeviceClipBounds();
|
|
SkDebugf("left:%d top:%d right:%d bottom:%d\n",
|
|
bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom);
|
|
SkPoint clipPoints[] = {{30, 130}, {120, 130}, {120, 230} };
|
|
SkPath clipPath;
|
|
clipPath.addPoly(clipPoints, SK_ARRAY_COUNT(clipPoints), true);
|
|
canvas->save();
|
|
canvas->clipPath(clipPath);
|
|
bounds = canvas->getDeviceClipBounds();
|
|
SkDebugf("left:%d top:%d right:%d bottom:%d\n",
|
|
bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom);
|
|
canvas->restore();
|
|
canvas->scale(1.f/2, 1.f/2);
|
|
canvas->clipPath(clipPath);
|
|
bounds = canvas->getDeviceClipBounds();
|
|
SkDebugf("left:%d top:%d right:%d bottom:%d\n",
|
|
bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom);
|
|
#StdOut
|
|
left:0 top:0 right:256 bottom:256
|
|
left:30 top:130 right:120 bottom:230
|
|
left:15 top:65 right:60 bottom:115
|
|
##
|
|
}
|
|
##
|
|
|
|
#ToDo some confusion on why with an identity Matrix local and device are different ##
|
|
#SeeAlso getLocalClipBounds getBaseLayerSize quickReject
|
|
|
|
# device canvas in example works around bug in fiddle ##
|
|
#Bug 6524
|
|
|
|
##
|
|
|
|
#Method bool getDeviceClipBounds(SkIRect* bounds) const
|
|
|
|
#In Clip
|
|
#Populate
|
|
|
|
#Example
|
|
void draw(SkCanvas* canvas) {
|
|
SkIRect bounds;
|
|
SkDebugf("device bounds empty = %s\n", canvas->getDeviceClipBounds(&bounds)
|
|
? "false" : "true");
|
|
SkPath path;
|
|
canvas->clipPath(path);
|
|
SkDebugf("device bounds empty = %s\n", canvas->getDeviceClipBounds(&bounds)
|
|
? "false" : "true");
|
|
}
|
|
#StdOut
|
|
device bounds empty = false
|
|
device bounds empty = true
|
|
##
|
|
##
|
|
|
|
#SeeAlso getLocalClipBounds getBaseLayerSize quickReject
|
|
|
|
##
|
|
|
|
#Subtopic Clip ##
|
|
|
|
# ------------------------------------------------------------------------------
|
|
#Subtopic Draw
|
|
#Line # draws into Canvas ##
|
|
##
|
|
|
|
#Method void drawColor(SkColor color, SkBlendMode mode = SkBlendMode::kSrcOver)
|
|
#In Draw
|
|
#Line # fills Clip with Color and Blend_Mode ##
|
|
#Populate
|
|
|
|
#Example
|
|
canvas->drawColor(SK_ColorRED);
|
|
canvas->clipRect(SkRect::MakeWH(150, 150));
|
|
canvas->drawColor(SkColorSetARGB(0x80, 0x00, 0xFF, 0x00), SkBlendMode::kPlus);
|
|
canvas->clipRect(SkRect::MakeWH(75, 75));
|
|
canvas->drawColor(SkColorSetARGB(0x80, 0x00, 0x00, 0xFF), SkBlendMode::kPlus);
|
|
##
|
|
|
|
#SeeAlso clear SkBitmap::erase drawPaint
|
|
|
|
##
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
#Method void clear(SkColor color)
|
|
#In Draw
|
|
#Line # fills Clip with Color ##
|
|
#Populate
|
|
|
|
#Example
|
|
void draw(SkCanvas* canvas) {
|
|
canvas->save();
|
|
canvas->clipRect(SkRect::MakeWH(256, 128));
|
|
canvas->clear(SkColorSetARGB(0x80, 0xFF, 0x00, 0x00));
|
|
canvas->restore();
|
|
canvas->save();
|
|
canvas->clipRect(SkRect::MakeWH(150, 192));
|
|
canvas->clear(SkColorSetARGB(0x80, 0x00, 0xFF, 0x00));
|
|
canvas->restore();
|
|
canvas->clipRect(SkRect::MakeWH(75, 256));
|
|
canvas->clear(SkColorSetARGB(0x80, 0x00, 0x00, 0xFF));
|
|
}
|
|
##
|
|
|
|
#SeeAlso drawColor SkBitmap::erase drawPaint
|
|
|
|
##
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
#Method void discard()
|
|
#In Utility
|
|
#Line # makes Canvas contents undefined ##
|
|
#Populate
|
|
|
|
#NoExample
|
|
##
|
|
|
|
#SeeAlso flush() GrContext::abandonContext
|
|
|
|
##
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
#Method void drawPaint(const SkPaint& paint)
|
|
#In Draw
|
|
#Line # fills Clip with Paint ##
|
|
#Populate
|
|
|
|
#Example
|
|
void draw(SkCanvas* canvas) {
|
|
SkColor colors[] = { SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE };
|
|
SkScalar pos[] = { 0, SK_Scalar1/2, SK_Scalar1 };
|
|
SkPaint paint;
|
|
paint.setShader(SkGradientShader::MakeSweep(256, 256, colors, pos, SK_ARRAY_COUNT(colors)));
|
|
canvas->drawPaint(paint);
|
|
}
|
|
##
|
|
|
|
#SeeAlso clear drawColor SkBitmap::erase
|
|
|
|
##
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
#Enum PointMode
|
|
#Line # sets drawPoints options ##
|
|
|
|
#Code
|
|
#Populate
|
|
##
|
|
|
|
Selects if an array of points are drawn as discrete points, as lines, or as
|
|
an open polygon.
|
|
|
|
#Const kPoints_PointMode 0
|
|
#Line # draw each point separately ##
|
|
##
|
|
|
|
#Const kLines_PointMode 1
|
|
#Line # draw each pair of points as a line segment ##
|
|
##
|
|
|
|
#Const kPolygon_PointMode 2
|
|
#Line # draw the array of points as a open polygon ##
|
|
##
|
|
|
|
#Example
|
|
#Description
|
|
The upper left corner shows three squares when drawn as points.
|
|
The upper right corner shows one line; when drawn as lines, two points are required per line.
|
|
The lower right corner shows two lines; when draw as polygon, no miter is drawn at the corner.
|
|
The lower left corner shows two lines with a miter when path contains polygon.
|
|
##
|
|
void draw(SkCanvas* canvas) {
|
|
SkPaint paint;
|
|
paint.setStyle(SkPaint::kStroke_Style);
|
|
paint.setStrokeWidth(10);
|
|
SkPoint points[] = {{64, 32}, {96, 96}, {32, 96}};
|
|
canvas->drawPoints(SkCanvas::kPoints_PointMode, 3, points, paint);
|
|
canvas->translate(128, 0);
|
|
canvas->drawPoints(SkCanvas::kLines_PointMode, 3, points, paint);
|
|
canvas->translate(0, 128);
|
|
canvas->drawPoints(SkCanvas::kPolygon_PointMode, 3, points, paint);
|
|
SkPath path;
|
|
path.addPoly(points, 3, false);
|
|
canvas->translate(-128, 0);
|
|
canvas->drawPath(path, paint);
|
|
}
|
|
##
|
|
|
|
#SeeAlso drawLine drawPoint drawPath
|
|
|
|
##
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
#Method void drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint)
|
|
#In Draw
|
|
#Line # draws array as points, lines, polygon ##
|
|
#Populate
|
|
|
|
#Example
|
|
#Height 200
|
|
#Description
|
|
#List
|
|
# The first column draws points. ##
|
|
# The second column draws points as lines. ##
|
|
# The third column draws points as a polygon. ##
|
|
# The fourth column draws points as a polygonal path. ##
|
|
# The first row uses a round cap and round join. ##
|
|
# The second row uses a square cap and a miter join. ##
|
|
# The third row uses a butt cap and a bevel join. ##
|
|
##
|
|
The transparent color makes multiple line draws visible;
|
|
the path is drawn all at once.
|
|
##
|
|
void draw(SkCanvas* canvas) {
|
|
SkPaint paint;
|
|
paint.setAntiAlias(true);
|
|
paint.setStyle(SkPaint::kStroke_Style);
|
|
paint.setStrokeWidth(10);
|
|
paint.setColor(0x80349a45);
|
|
const SkPoint points[] = {{32, 16}, {48, 48}, {16, 32}};
|
|
const SkPaint::Join join[] = { SkPaint::kRound_Join,
|
|
SkPaint::kMiter_Join,
|
|
SkPaint::kBevel_Join };
|
|
int joinIndex = 0;
|
|
SkPath path;
|
|
path.addPoly(points, 3, false);
|
|
for (const auto cap : { SkPaint::kRound_Cap, SkPaint::kSquare_Cap, SkPaint::kButt_Cap } ) {
|
|
paint.setStrokeCap(cap);
|
|
paint.setStrokeJoin(join[joinIndex++]);
|
|
for (const auto mode : { SkCanvas::kPoints_PointMode,
|
|
SkCanvas::kLines_PointMode,
|
|
SkCanvas::kPolygon_PointMode } ) {
|
|
canvas->drawPoints(mode, 3, points, paint);
|
|
canvas->translate(64, 0);
|
|
}
|
|
canvas->drawPath(path, paint);
|
|
canvas->translate(-192, 64);
|
|
}
|
|
}
|
|
##
|
|
|
|
#SeeAlso drawLine drawPoint drawPath
|
|
|
|
##
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
#Method void drawPoint(SkScalar x, SkScalar y, const SkPaint& paint)
|
|
#In Draw
|
|
#Line # draws point at (x, y) position ##
|
|
#Populate
|
|
|
|
#Example
|
|
void draw(SkCanvas* canvas) {
|
|
SkPaint paint;
|
|
paint.setAntiAlias(true);
|
|
paint.setColor(0x80349a45);
|
|
paint.setStyle(SkPaint::kStroke_Style);
|
|
paint.setStrokeWidth(100);
|
|
paint.setStrokeCap(SkPaint::kRound_Cap);
|
|
canvas->scale(1, 1.2f);
|
|
canvas->drawPoint(64, 96, paint);
|
|
canvas->scale(.6f, .8f);
|
|
paint.setColor(SK_ColorWHITE);
|
|
canvas->drawPoint(106, 120, paint);
|
|
}
|
|
##
|
|
|
|
#SeeAlso drawPoints drawCircle drawRect drawLine drawPath
|
|
|
|
##
|
|
|
|
#Method void drawPoint(SkPoint p, const SkPaint& paint)
|
|
#Populate
|
|
|
|
#Example
|
|
void draw(SkCanvas* canvas) {
|
|
SkPaint paint;
|
|
paint.setAntiAlias(true);
|
|
paint.setColor(0x80349a45);
|
|
paint.setStyle(SkPaint::kStroke_Style);
|
|
paint.setStrokeWidth(100);
|
|
paint.setStrokeCap(SkPaint::kSquare_Cap);
|
|
canvas->scale(1, 1.2f);
|
|
canvas->drawPoint({64, 96}, paint);
|
|
canvas->scale(.6f, .8f);
|
|
paint.setColor(SK_ColorWHITE);
|
|
canvas->drawPoint(106, 120, paint);
|
|
}
|
|
##
|
|
|
|
#SeeAlso drawPoints drawCircle drawRect drawLine drawPath
|
|
|
|
##
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
#Method void drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1, const SkPaint& paint)
|
|
#In Draw
|
|
#Line # draws line segment between two points ##
|
|
#Populate
|
|
|
|
#Example
|
|
SkPaint paint;
|
|
paint.setAntiAlias(true);
|
|
paint.setColor(0xFF9a67be);
|
|
paint.setStrokeWidth(20);
|
|
canvas->skew(1, 0);
|
|
canvas->drawLine(32, 96, 32, 160, paint);
|
|
canvas->skew(-2, 0);
|
|
canvas->drawLine(288, 96, 288, 160, paint);
|
|
##
|
|
|
|
#SeeAlso drawPoint drawCircle drawRect drawPath
|
|
|
|
##
|
|
|
|
#Method void drawLine(SkPoint p0, SkPoint p1, const SkPaint& paint)
|
|
#Populate
|
|
|
|
#Example
|
|
SkPaint paint;
|
|
paint.setAntiAlias(true);
|
|
paint.setColor(0xFF9a67be);
|
|
paint.setStrokeWidth(20);
|
|
canvas->skew(1, 0);
|
|
canvas->drawLine({32, 96}, {32, 160}, paint);
|
|
canvas->skew(-2, 0);
|
|
canvas->drawLine({288, 96}, {288, 160}, paint);
|
|
##
|
|
|
|
#SeeAlso drawPoint drawCircle drawRect drawPath
|
|
|
|
##
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
#Method void drawRect(const SkRect& rect, const SkPaint& paint)
|
|
#In Draw
|
|
#Line # draws Rect using Clip, Matrix, and Paint ##
|
|
#Populate
|
|
|
|
#Example
|
|
void draw(SkCanvas* canvas) {
|
|
SkPoint rectPts[] = { {64, 48}, {192, 160} };
|
|
SkPaint paint;
|
|
paint.setAntiAlias(true);
|
|
paint.setStyle(SkPaint::kStroke_Style);
|
|
paint.setStrokeWidth(20);
|
|
paint.setStrokeJoin(SkPaint::kRound_Join);
|
|
SkMatrix rotator;
|
|
rotator.setRotate(30, 128, 128);
|
|
for (auto color : { SK_ColorRED, SK_ColorBLUE, SK_ColorYELLOW, SK_ColorMAGENTA } ) {
|
|
paint.setColor(color);
|
|
SkRect rect;
|
|
rect.set(rectPts[0], rectPts[1]);
|
|
canvas->drawRect(rect, paint);
|
|
rotator.mapPoints(rectPts, 2);
|
|
}
|
|
}
|
|
##
|
|
|
|
#SeeAlso drawIRect drawRRect drawRoundRect drawRegion drawPath drawLine
|
|
|
|
##
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
#Method void drawIRect(const SkIRect& rect, const SkPaint& paint)
|
|
#In Draw
|
|
#Line # draws IRect using Clip, Matrix, and Paint ##
|
|
#Populate
|
|
|
|
#Example
|
|
SkIRect rect = { 64, 48, 192, 160 };
|
|
SkPaint paint;
|
|
paint.setAntiAlias(true);
|
|
paint.setStyle(SkPaint::kStroke_Style);
|
|
paint.setStrokeWidth(20);
|
|
paint.setStrokeJoin(SkPaint::kRound_Join);
|
|
for (auto color : { SK_ColorRED, SK_ColorBLUE, SK_ColorYELLOW, SK_ColorMAGENTA } ) {
|
|
paint.setColor(color);
|
|
canvas->drawIRect(rect, paint);
|
|
canvas->rotate(30, 128, 128);
|
|
}
|
|
##
|
|
|
|
#SeeAlso drawRect drawRRect drawRoundRect drawRegion drawPath drawLine
|
|
|
|
##
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
#Method void drawRegion(const SkRegion& region, const SkPaint& paint)
|
|
#In Draw
|
|
#Line # draws Region using Clip, Matrix, and Paint ##
|
|
#Populate
|
|
|
|
#Example
|
|
void draw(SkCanvas* canvas) {
|
|
SkRegion region;
|
|
region.op( 10, 10, 50, 50, SkRegion::kUnion_Op);
|
|
region.op( 10, 50, 90, 90, SkRegion::kUnion_Op);
|
|
SkPaint paint;
|
|
paint.setAntiAlias(true);
|
|
paint.setStyle(SkPaint::kStroke_Style);
|
|
paint.setStrokeWidth(20);
|
|
paint.setStrokeJoin(SkPaint::kRound_Join);
|
|
canvas->drawRegion(region, paint);
|
|
}
|
|
##
|
|
|
|
#SeeAlso drawRect drawIRect drawPath
|
|
|
|
##
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
#Method void drawOval(const SkRect& oval, const SkPaint& paint)
|
|
#In Draw
|
|
#Line # draws Oval using Clip, Matrix, and Paint ##
|
|
#Populate
|
|
|
|
#Example
|
|
void draw(SkCanvas* canvas) {
|
|
canvas->clear(0xFF3f5f9f);
|
|
SkColor kColor1 = SkColorSetARGB(0xff, 0xff, 0x7f, 0);
|
|
SkColor g1Colors[] = { kColor1, SkColorSetA(kColor1, 0x20) };
|
|
SkPoint g1Points[] = { { 0, 0 }, { 0, 100 } };
|
|
SkScalar pos[] = { 0.2f, 1.0f };
|
|
SkRect bounds = SkRect::MakeWH(80, 70);
|
|
SkPaint paint;
|
|
paint.setAntiAlias(true);
|
|
paint.setShader(SkGradientShader::MakeLinear(g1Points, g1Colors, pos, SK_ARRAY_COUNT(g1Colors),
|
|
SkShader::kClamp_TileMode));
|
|
canvas->drawOval(bounds , paint);
|
|
}
|
|
##
|
|
|
|
#SeeAlso drawCircle drawPoint drawPath drawRRect drawRoundRect
|
|
|
|
##
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
#Method void drawRRect(const SkRRect& rrect, const SkPaint& paint)
|
|
#In Draw
|
|
#Line # draws Round_Rect using Clip, Matrix, and Paint ##
|
|
#Populate
|
|
|
|
#Example
|
|
void draw(SkCanvas* canvas) {
|
|
SkPaint paint;
|
|
paint.setAntiAlias(true);
|
|
SkRect outer = {30, 40, 210, 220};
|
|
SkRect radii = {30, 50, 70, 90 };
|
|
SkRRect rRect;
|
|
rRect.setNinePatch(outer, radii.fLeft, radii.fTop, radii.fRight, radii.fBottom);
|
|
canvas->drawRRect(rRect, paint);
|
|
paint.setColor(SK_ColorWHITE);
|
|
canvas->drawLine(outer.fLeft + radii.fLeft, outer.fTop,
|
|
outer.fLeft + radii.fLeft, outer.fBottom, paint);
|
|
canvas->drawLine(outer.fRight - radii.fRight, outer.fTop,
|
|
outer.fRight - radii.fRight, outer.fBottom, paint);
|
|
canvas->drawLine(outer.fLeft, outer.fTop + radii.fTop,
|
|
outer.fRight, outer.fTop + radii.fTop, paint);
|
|
canvas->drawLine(outer.fLeft, outer.fBottom - radii.fBottom,
|
|
outer.fRight, outer.fBottom - radii.fBottom, paint);
|
|
}
|
|
##
|
|
|
|
#SeeAlso drawRect drawRoundRect drawDRRect drawCircle drawOval drawPath
|
|
|
|
##
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
#Method void drawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint)
|
|
#In Draw
|
|
#Line # draws double Round_Rect stroked or filled ##
|
|
#Populate
|
|
|
|
#Example
|
|
void draw(SkCanvas* canvas) {
|
|
SkRRect outer = SkRRect::MakeRect({20, 40, 210, 200});
|
|
SkRRect inner = SkRRect::MakeOval({60, 70, 170, 160});
|
|
SkPaint paint;
|
|
canvas->drawDRRect(outer, inner, paint);
|
|
}
|
|
##
|
|
|
|
#Example
|
|
#Description
|
|
Outer Rect has no corner radii, but stroke join is rounded.
|
|
Inner Round_Rect has corner radii; outset stroke increases radii of corners.
|
|
Stroke join does not affect inner Round_Rect since it has no sharp corners.
|
|
##
|
|
void draw(SkCanvas* canvas) {
|
|
SkRRect outer = SkRRect::MakeRect({20, 40, 210, 200});
|
|
SkRRect inner = SkRRect::MakeRectXY({60, 70, 170, 160}, 10, 10);
|
|
SkPaint paint;
|
|
paint.setAntiAlias(true);
|
|
paint.setStyle(SkPaint::kStroke_Style);
|
|
paint.setStrokeWidth(20);
|
|
paint.setStrokeJoin(SkPaint::kRound_Join);
|
|
canvas->drawDRRect(outer, inner, paint);
|
|
paint.setStrokeWidth(1);
|
|
paint.setColor(SK_ColorWHITE);
|
|
canvas->drawDRRect(outer, inner, paint);
|
|
}
|
|
##
|
|
|
|
#SeeAlso drawRect drawRoundRect drawRRect drawCircle drawOval drawPath
|
|
|
|
##
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
#Method void drawCircle(SkScalar cx, SkScalar cy, SkScalar radius, const SkPaint& paint)
|
|
#In Draw
|
|
#Line # draws Circle using Clip, Matrix, and Paint ##
|
|
#Populate
|
|
|
|
#Example
|
|
void draw(SkCanvas* canvas) {
|
|
SkPaint paint;
|
|
paint.setAntiAlias(true);
|
|
canvas->drawCircle(128, 128, 90, paint);
|
|
paint.setColor(SK_ColorWHITE);
|
|
canvas->drawCircle(86, 86, 20, paint);
|
|
canvas->drawCircle(160, 76, 20, paint);
|
|
canvas->drawCircle(140, 150, 35, paint);
|
|
}
|
|
##
|
|
|
|
#SeeAlso drawOval drawRRect drawRoundRect drawPath drawArc drawPoint drawLine
|
|
|
|
##
|
|
|
|
#Method void drawCircle(SkPoint center, SkScalar radius, const SkPaint& paint)
|
|
#Populate
|
|
|
|
#Example
|
|
void draw(SkCanvas* canvas) {
|
|
SkPaint paint;
|
|
paint.setAntiAlias(true);
|
|
canvas->drawCircle(128, 128, 90, paint);
|
|
paint.setColor(SK_ColorWHITE);
|
|
canvas->drawCircle({86, 86}, 20, paint);
|
|
canvas->drawCircle({160, 76}, 20, paint);
|
|
canvas->drawCircle({140, 150}, 35, paint);
|
|
}
|
|
##
|
|
|
|
#SeeAlso drawOval drawRRect drawRoundRect drawPath drawArc drawPoint drawLine
|
|
|
|
##
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
#Method void drawArc(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle,
|
|
bool useCenter, const SkPaint& paint)
|
|
#In Draw
|
|
#Line # draws Arc using Clip, Matrix, and Paint ##
|
|
#Populate
|
|
|
|
#Example
|
|
void draw(SkCanvas* canvas) {
|
|
SkPaint paint;
|
|
paint.setAntiAlias(true);
|
|
SkRect oval = { 4, 4, 60, 60};
|
|
for (auto useCenter : { false, true } ) {
|
|
for (auto style : { SkPaint::kFill_Style, SkPaint::kStroke_Style } ) {
|
|
paint.setStyle(style);
|
|
for (auto degrees : { 45, 90, 180, 360} ) {
|
|
canvas->drawArc(oval, 0, degrees , useCenter, paint);
|
|
canvas->translate(64, 0);
|
|
}
|
|
canvas->translate(-256, 64);
|
|
}
|
|
}
|
|
}
|
|
##
|
|
|
|
#Example
|
|
#Height 64
|
|
void draw(SkCanvas* canvas) {
|
|
SkPaint paint;
|
|
paint.setAntiAlias(true);
|
|
paint.setStyle(SkPaint::kStroke_Style);
|
|
paint.setStrokeWidth(4);
|
|
SkRect oval = { 4, 4, 60, 60};
|
|
float intervals[] = { 5, 5 };
|
|
paint.setPathEffect(SkDashPathEffect::Make(intervals, 2, 2.5f));
|
|
for (auto degrees : { 270, 360, 540, 720 } ) {
|
|
canvas->drawArc(oval, 0, degrees, false, paint);
|
|
canvas->translate(64, 0);
|
|
}
|
|
}
|
|
##
|
|
|
|
#SeeAlso SkPath::arcTo drawCircle drawOval drawPath
|
|
|
|
##
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
#Method void drawRoundRect(const SkRect& rect, SkScalar rx, SkScalar ry, const SkPaint& paint)
|
|
#In Draw
|
|
#Line # draws Round_Rect using Clip, Matrix, and Paint ##
|
|
#Populate
|
|
|
|
#Example
|
|
#Description
|
|
Top row has a zero radius a generates a rectangle.
|
|
Second row radii sum to less than sides.
|
|
Third row radii sum equals sides.
|
|
Fourth row radii sum exceeds sides; radii are scaled to fit.
|
|
##
|
|
void draw(SkCanvas* canvas) {
|
|
SkVector radii[] = { {0, 20}, {10, 10}, {10, 20}, {10, 40} };
|
|
SkPaint paint;
|
|
paint.setStrokeWidth(15);
|
|
paint.setStrokeJoin(SkPaint::kRound_Join);
|
|
paint.setAntiAlias(true);
|
|
for (auto style : { SkPaint::kStroke_Style, SkPaint::kFill_Style } ) {
|
|
paint.setStyle(style );
|
|
for (size_t i = 0; i < SK_ARRAY_COUNT(radii); ++i) {
|
|
canvas->drawRoundRect({10, 10, 60, 40}, radii[i].fX, radii[i].fY, paint);
|
|
canvas->translate(0, 60);
|
|
}
|
|
canvas->translate(80, -240);
|
|
}
|
|
}
|
|
##
|
|
|
|
#SeeAlso drawRRect drawRect drawDRRect drawPath drawCircle drawOval drawPoint
|
|
|
|
##
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
#Method void drawPath(const SkPath& path, const SkPaint& paint)
|
|
#In Draw
|
|
#Line # draws Path using Clip, Matrix, and Paint ##
|
|
#Populate
|
|
|
|
#Example
|
|
#Description
|
|
Top rows draw stroked path with combinations of joins and caps. The open contour
|
|
is affected by caps; the closed contour is affected by joins.
|
|
Bottom row draws fill the same for open and closed contour.
|
|
First bottom column shows winding fills overlap.
|
|
Second bottom column shows even odd fills exclude overlap.
|
|
Third bottom column shows inverse winding fills area outside both contours.
|
|
##
|
|
void draw(SkCanvas* canvas) {
|
|
SkPath path;
|
|
path.moveTo(20, 20);
|
|
path.quadTo(60, 20, 60, 60);
|
|
path.close();
|
|
path.moveTo(60, 20);
|
|
path.quadTo(60, 60, 20, 60);
|
|
SkPaint paint;
|
|
paint.setStrokeWidth(10);
|
|
paint.setAntiAlias(true);
|
|
paint.setStyle(SkPaint::kStroke_Style);
|
|
for (auto join: { SkPaint::kBevel_Join, SkPaint::kRound_Join, SkPaint::kMiter_Join } ) {
|
|
paint.setStrokeJoin(join);
|
|
for (auto cap: { SkPaint::kButt_Cap, SkPaint::kSquare_Cap, SkPaint::kRound_Cap } ) {
|
|
paint.setStrokeCap(cap);
|
|
canvas->drawPath(path, paint);
|
|
canvas->translate(80, 0);
|
|
}
|
|
canvas->translate(-240, 60);
|
|
}
|
|
paint.setStyle(SkPaint::kFill_Style);
|
|
for (auto fill : { SkPath::kWinding_FillType,
|
|
SkPath::kEvenOdd_FillType,
|
|
SkPath::kInverseWinding_FillType } ) {
|
|
path.setFillType(fill);
|
|
canvas->save();
|
|
canvas->clipRect({0, 10, 80, 70});
|
|
canvas->drawPath(path, paint);
|
|
canvas->restore();
|
|
canvas->translate(80, 0);
|
|
}
|
|
}
|
|
##
|
|
|
|
#SeeAlso SkPath drawLine drawArc drawRect drawPoints
|
|
|
|
##
|
|
|
|
# ------------------------------------------------------------------------------
|
|
#Subtopic Draw_Image
|
|
#Line # draws Image to Canvas ##
|
|
|
|
drawImage, drawImageRect, and drawImageNine can be called with a bare pointer or
|
|
a smart pointer as a convenience. The pairs of calls are otherwise identical.
|
|
|
|
#Method void drawImage(const SkImage* image, SkScalar left, SkScalar top, const SkPaint* paint = nullptr)
|
|
#In Draw_Image
|
|
#In Draw
|
|
#Line # draws Image at (x, y) position ##
|
|
#Populate
|
|
|
|
#Example
|
|
#Height 64
|
|
#Image 4
|
|
void draw(SkCanvas* canvas) {
|
|
// sk_sp<SkImage> image;
|
|
SkImage* imagePtr = image.get();
|
|
canvas->drawImage(imagePtr, 0, 0);
|
|
SkPaint paint;
|
|
canvas->drawImage(imagePtr, 80, 0, &paint);
|
|
paint.setAlpha(0x80);
|
|
canvas->drawImage(imagePtr, 160, 0, &paint);
|
|
}
|
|
##
|
|
|
|
#SeeAlso drawBitmap drawImageLattice drawImageNine drawImageRect SkPaint::setImageFilter
|
|
|
|
##
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
#Method void drawImage(const sk_sp<SkImage>& image, SkScalar left, SkScalar top,
|
|
const SkPaint* paint = nullptr)
|
|
#Populate
|
|
|
|
#Example
|
|
#Height 64
|
|
#Image 4
|
|
void draw(SkCanvas* canvas) {
|
|
// sk_sp<SkImage> image;
|
|
canvas->drawImage(image, 0, 0);
|
|
SkPaint paint;
|
|
canvas->drawImage(image, 80, 0, &paint);
|
|
paint.setAlpha(0x80);
|
|
canvas->drawImage(image, 160, 0, &paint);
|
|
}
|
|
##
|
|
|
|
#SeeAlso drawBitmap drawImageLattice drawImageNine drawImageRect SkPaint::setImageFilter
|
|
|
|
##
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
#Enum SrcRectConstraint
|
|
#Line # sets drawImageRect options ##
|
|
|
|
#Code
|
|
#Populate
|
|
##
|
|
|
|
SrcRectConstraint controls the behavior at the edge of source Rect,
|
|
provided to drawImageRect, trading off speed for precision.
|
|
|
|
Image_Filter in Paint may sample multiple pixels in the image. Source Rect
|
|
restricts the bounds of pixels that may be read. Image_Filter may slow down if
|
|
it cannot read outside the bounds, when sampling near the edge of source Rect.
|
|
SrcRectConstraint specifies whether an Image_Filter is allowed to read pixels
|
|
outside source Rect.
|
|
|
|
#Const kStrict_SrcRectConstraint 0
|
|
#Line # sample only inside bounds; slower ##
|
|
Requires Image_Filter to respect source Rect,
|
|
sampling only inside of its bounds, possibly with a performance penalty.
|
|
##
|
|
|
|
#Const kFast_SrcRectConstraint 1
|
|
#Line # sample outside bounds; faster ##
|
|
Permits Image_Filter to sample outside of source Rect
|
|
by half the width of Image_Filter, permitting it to run faster but with
|
|
error at the image edges.
|
|
##
|
|
|
|
#Example
|
|
#Height 64
|
|
#Description
|
|
redBorder contains a black and white checkerboard bordered by red.
|
|
redBorder is drawn scaled by 16 on the left.
|
|
The middle and right bitmaps are filtered checkerboards.
|
|
Drawing the checkerboard with kStrict_SrcRectConstraint shows only a blur of black and white.
|
|
Drawing the checkerboard with kFast_SrcRectConstraint allows red to bleed in the corners.
|
|
##
|
|
void draw(SkCanvas* canvas) {
|
|
SkBitmap redBorder;
|
|
redBorder.allocPixels(SkImageInfo::MakeN32Premul(4, 4));
|
|
SkCanvas checkRed(redBorder);
|
|
checkRed.clear(SK_ColorRED);
|
|
uint32_t checkers[][2] = { { SK_ColorBLACK, SK_ColorWHITE },
|
|
{ SK_ColorWHITE, SK_ColorBLACK } };
|
|
checkRed.writePixels(
|
|
SkImageInfo::MakeN32Premul(2, 2), (void*) checkers, sizeof(checkers[0]), 1, 1);
|
|
canvas->scale(16, 16);
|
|
canvas->drawBitmap(redBorder, 0, 0, nullptr);
|
|
canvas->resetMatrix();
|
|
sk_sp<SkImage> image = SkImage::MakeFromBitmap(redBorder);
|
|
SkPaint lowPaint;
|
|
lowPaint.setFilterQuality(kLow_SkFilterQuality);
|
|
for (auto constraint : { SkCanvas::kStrict_SrcRectConstraint,
|
|
SkCanvas::kFast_SrcRectConstraint } ) {
|
|
canvas->translate(80, 0);
|
|
canvas->drawImageRect(image.get(), SkRect::MakeLTRB(1, 1, 3, 3),
|
|
SkRect::MakeLTRB(16, 16, 48, 48), &lowPaint, constraint);
|
|
}
|
|
}
|
|
##
|
|
|
|
#SeeAlso drawImageRect drawImage SkPaint::setImageFilter
|
|
|
|
##
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
#Method void drawImageRect(const SkImage* image, const SkRect& src, const SkRect& dst,
|
|
const SkPaint* paint,
|
|
SrcRectConstraint constraint = kStrict_SrcRectConstraint)
|
|
#In Draw_Image
|
|
#In Draw
|
|
#Line # draws Image, source Rect to destination Rect ##
|
|
#Populate
|
|
|
|
#Example
|
|
#Height 64
|
|
#Description
|
|
The left bitmap draws with Paint default kNone_SkFilterQuality, and stays within
|
|
its bounds; there is no bleeding with kFast_SrcRectConstraint.
|
|
the middle and right bitmaps draw with kLow_SkFilterQuality; with
|
|
kStrict_SrcRectConstraint, the filter remains within the checkerboard, and
|
|
with kFast_SrcRectConstraint red bleeds on the edges.
|
|
##
|
|
void draw(SkCanvas* canvas) {
|
|
uint32_t pixels[][4] = {
|
|
{ 0xFFFF0000, 0xFFFF0000, 0xFFFF0000, 0xFFFF0000 },
|
|
{ 0xFFFF0000, 0xFF000000, 0xFFFFFFFF, 0xFFFF0000 },
|
|
{ 0xFFFF0000, 0xFFFFFFFF, 0xFF000000, 0xFFFF0000 },
|
|
{ 0xFFFF0000, 0xFFFF0000, 0xFFFF0000, 0xFFFF0000 } };
|
|
SkBitmap redBorder;
|
|
redBorder.installPixels(SkImageInfo::MakeN32Premul(4, 4),
|
|
(void*) pixels, sizeof(pixels[0]));
|
|
sk_sp<SkImage> image = SkImage::MakeFromBitmap(redBorder);
|
|
SkPaint lowPaint;
|
|
for (auto constraint : {
|
|
SkCanvas::kFast_SrcRectConstraint,
|
|
SkCanvas::kStrict_SrcRectConstraint,
|
|
SkCanvas::kFast_SrcRectConstraint } ) {
|
|
canvas->drawImageRect(image.get(), SkRect::MakeLTRB(1, 1, 3, 3),
|
|
SkRect::MakeLTRB(16, 16, 48, 48), &lowPaint, constraint);
|
|
lowPaint.setFilterQuality(kLow_SkFilterQuality);
|
|
canvas->translate(80, 0);
|
|
}
|
|
}
|
|
##
|
|
|
|
#SeeAlso SrcRectConstraint drawImage drawImageLattice drawImageNine
|
|
|
|
##
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
#Method void drawImageRect(const SkImage* image, const SkIRect& isrc, const SkRect& dst,
|
|
const SkPaint* paint, SrcRectConstraint constraint = kStrict_SrcRectConstraint)
|
|
#In Draw_Image
|
|
#In Draw
|
|
#Populate
|
|
|
|
#Example
|
|
#Image 4
|
|
void draw(SkCanvas* canvas) {
|
|
// sk_sp<SkImage> image;
|
|
for (auto i : { 1, 2, 4, 8 } ) {
|
|
canvas->drawImageRect(image.get(), SkIRect::MakeLTRB(0, 0, 100, 100),
|
|
SkRect::MakeXYWH(i * 20, i * 20, i * 20, i * 20), nullptr);
|
|
}
|
|
}
|
|
##
|
|
|
|
#SeeAlso SrcRectConstraint drawImage drawImageLattice drawImageNine
|
|
|
|
##
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
#Method void drawImageRect(const SkImage* image, const SkRect& dst, const SkPaint* paint)
|
|
#In Draw_Image
|
|
#In Draw
|
|
#Populate
|
|
|
|
#Example
|
|
#Image 4
|
|
void draw(SkCanvas* canvas) {
|
|
// sk_sp<SkImage> image;
|
|
for (auto i : { 20, 40, 80, 160 } ) {
|
|
canvas->drawImageRect(image.get(), SkRect::MakeXYWH(i, i, i, i), nullptr);
|
|
}
|
|
}
|
|
##
|
|
|
|
#SeeAlso SrcRectConstraint drawImage drawImageLattice drawImageNine
|
|
|
|
##
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
#Method void drawImageRect(const sk_sp<SkImage>& image, const SkRect& src, const SkRect& dst,
|
|
const SkPaint* paint,
|
|
SrcRectConstraint constraint = kStrict_SrcRectConstraint)
|
|
#In Draw_Image
|
|
#In Draw
|
|
#Populate
|
|
|
|
#Example
|
|
#Height 64
|
|
#Description
|
|
Canvas scales and translates; transformation from src to dst also scales.
|
|
The two matrices are concatenated to create the final transformation.
|
|
##
|
|
void draw(SkCanvas* canvas) {
|
|
uint32_t pixels[][2] = { { SK_ColorBLACK, SK_ColorWHITE },
|
|
{ SK_ColorWHITE, SK_ColorBLACK } };
|
|
SkBitmap bitmap;
|
|
bitmap.installPixels(SkImageInfo::MakeN32Premul(2, 2),
|
|
(void*) pixels, sizeof(pixels[0]));
|
|
sk_sp<SkImage> image = SkImage::MakeFromBitmap(bitmap);
|
|
SkPaint paint;
|
|
canvas->scale(4, 4);
|
|
for (auto alpha : { 50, 100, 150, 255 } ) {
|
|
paint.setAlpha(alpha);
|
|
canvas->drawImageRect(image, SkRect::MakeWH(2, 2), SkRect::MakeWH(8, 8), &paint);
|
|
canvas->translate(8, 0);
|
|
}
|
|
}
|
|
##
|
|
|
|
#SeeAlso SrcRectConstraint drawImage drawImageLattice drawImageNine
|
|
|
|
##
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
#Method void drawImageRect(const sk_sp<SkImage>& image, const SkIRect& isrc, const SkRect& dst,
|
|
const SkPaint* paint, SrcRectConstraint constraint = kStrict_SrcRectConstraint)
|
|
#In Draw_Image
|
|
#In Draw
|
|
#Populate
|
|
|
|
#Example
|
|
#Height 64
|
|
void draw(SkCanvas* canvas) {
|
|
uint32_t pixels[][2] = { { 0x00000000, 0x55555555},
|
|
{ 0xAAAAAAAA, 0xFFFFFFFF} };
|
|
SkBitmap bitmap;
|
|
bitmap.installPixels(SkImageInfo::MakeN32Premul(2, 2),
|
|
(void*) pixels, sizeof(pixels[0]));
|
|
sk_sp<SkImage> image = SkImage::MakeFromBitmap(bitmap);
|
|
SkPaint paint;
|
|
canvas->scale(4, 4);
|
|
for (auto color : { SK_ColorRED, SK_ColorBLUE, SK_ColorGREEN } ) {
|
|
paint.setColorFilter(SkColorFilter::MakeModeFilter(color, SkBlendMode::kPlus));
|
|
canvas->drawImageRect(image, SkIRect::MakeWH(2, 2), SkRect::MakeWH(8, 8), &paint);
|
|
canvas->translate(8, 0);
|
|
}
|
|
}
|
|
##
|
|
|
|
#SeeAlso SrcRectConstraint drawImage drawImageLattice drawImageNine
|
|
|
|
##
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
#Method void drawImageRect(const sk_sp<SkImage>& image, const SkRect& dst, const SkPaint* paint)
|
|
#In Draw_Image
|
|
#In Draw
|
|
#Populate
|
|
|
|
#Example
|
|
#Height 64
|
|
void draw(SkCanvas* canvas) {
|
|
uint32_t pixels[][2] = { { 0x00000000, 0x55550000},
|
|
{ 0xAAAA0000, 0xFFFF0000} };
|
|
SkBitmap bitmap;
|
|
bitmap.installPixels(SkImageInfo::MakeN32Premul(2, 2),
|
|
(void*) pixels, sizeof(pixels[0]));
|
|
sk_sp<SkImage> image = SkImage::MakeFromBitmap(bitmap);
|
|
SkPaint paint;
|
|
canvas->scale(4, 4);
|
|
for (auto color : { SK_ColorRED, SK_ColorBLUE, SK_ColorGREEN } ) {
|
|
paint.setColorFilter(SkColorFilter::MakeModeFilter(color, SkBlendMode::kPlus));
|
|
canvas->drawImageRect(image, SkRect::MakeWH(8, 8), &paint);
|
|
canvas->translate(8, 0);
|
|
}
|
|
}
|
|
##
|
|
|
|
#SeeAlso SrcRectConstraint drawImage drawImageLattice drawImageNine
|
|
|
|
##
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
#Method void drawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
|
|
const SkPaint* paint = nullptr)
|
|
#In Draw_Image
|
|
#In Draw
|
|
#Line # draws Nine_Patch Image ##
|
|
|
|
Draws Image image stretched proportionally to fit into Rect dst.
|
|
IRect center divides the image into nine sections: four sides, four corners, and
|
|
the center. Corners are unmodified or scaled down proportionately if their sides
|
|
are larger than dst; center and four sides are scaled to fit remaining space, if any.
|
|
|
|
Additionally transform draw using Clip, Matrix, and optional Paint paint.
|
|
|
|
#paint_as_used_by_draw_lattice_or_draw_nine(image)#
|
|
|
|
If generated mask extends beyond image bounds, replicate image edge colors, just
|
|
as Shader made from SkImage::makeShader with SkShader::kClamp_TileMode set
|
|
replicates the image edge color when it samples outside of its bounds.
|
|
|
|
#Param image Image containing pixels, dimensions, and format ##
|
|
#Param center IRect edge of image corners and sides ##
|
|
#Param dst destination Rect of image to draw to ##
|
|
#Param paint Paint containing Blend_Mode, Color_Filter, Image_Filter,
|
|
and so on; or nullptr
|
|
##
|
|
|
|
#Example
|
|
#Height 128
|
|
#Description
|
|
The leftmost image is smaller than center; only corners are drawn, all scaled to fit.
|
|
The second image equals the size of center; only corners are drawn without scaling.
|
|
The remaining images are larger than center. All corners draw without scaling.
|
|
The sides and center are scaled if needed to take up the remaining space.
|
|
##
|
|
void draw(SkCanvas* canvas) {
|
|
SkIRect center = { 20, 10, 50, 40 };
|
|
SkBitmap bitmap;
|
|
bitmap.allocPixels(SkImageInfo::MakeN32Premul(60, 60));
|
|
SkCanvas bitCanvas(bitmap);
|
|
SkPaint paint;
|
|
SkColor gray = 0xFF000000;
|
|
int left = 0;
|
|
for (auto right: { center.fLeft, center.fRight, bitmap.width() } ) {
|
|
int top = 0;
|
|
for (auto bottom: { center.fTop, center.fBottom, bitmap.height() } ) {
|
|
paint.setColor(gray);
|
|
bitCanvas.drawIRect(SkIRect::MakeLTRB(left, top, right, bottom), paint);
|
|
gray += 0x001f1f1f;
|
|
top = bottom;
|
|
}
|
|
left = right;
|
|
}
|
|
sk_sp<SkImage> image = SkImage::MakeFromBitmap(bitmap);
|
|
SkImage* imagePtr = image.get();
|
|
for (auto dest: { 20, 30, 40, 60, 90 } ) {
|
|
canvas->drawImageNine(imagePtr, center, SkRect::MakeWH(dest, dest), nullptr);
|
|
canvas->translate(dest + 4, 0);
|
|
}
|
|
}
|
|
##
|
|
|
|
#SeeAlso drawImage drawBitmapNine drawImageLattice drawImageRect
|
|
|
|
##
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
#Method void drawImageNine(const sk_sp<SkImage>& image, const SkIRect& center, const SkRect& dst,
|
|
const SkPaint* paint = nullptr)
|
|
#In Draw_Image
|
|
#In Draw
|
|
Draws Image image stretched proportionally to fit into Rect dst.
|
|
IRect center divides the image into nine sections: four sides, four corners, and
|
|
the center. Corners are not scaled, or scaled down proportionately if their sides
|
|
are larger than dst; center and four sides are scaled to fit remaining space, if any.
|
|
|
|
Additionally transform draw using Clip, Matrix, and optional Paint paint.
|
|
|
|
#paint_as_used_by_draw_lattice_or_draw_nine(image)#
|
|
|
|
If generated mask extends beyond image bounds, replicate image edge colors, just
|
|
as Shader made from SkImage::makeShader with SkShader::kClamp_TileMode set
|
|
replicates the image edge color when it samples outside of its bounds.
|
|
|
|
#Param image Image containing pixels, dimensions, and format ##
|
|
#Param center IRect edge of image corners and sides ##
|
|
#Param dst destination Rect of image to draw to ##
|
|
#Param paint Paint containing Blend_Mode, Color_Filter, Image_Filter,
|
|
and so on; or nullptr
|
|
##
|
|
|
|
#Example
|
|
#Height 128
|
|
#Description
|
|
The two leftmost images has four corners and sides to the left and right of center.
|
|
The leftmost image scales the width of corners proportionately to fit.
|
|
The third and fourth image corners are not scaled; the sides and center are scaled to
|
|
fill the remaining space.
|
|
The rightmost image has four corners scaled vertically to fit, and uses sides above
|
|
and below center to fill the remaining space.
|
|
##
|
|
void draw(SkCanvas* canvas) {
|
|
SkIRect center = { 20, 10, 50, 40 };
|
|
SkBitmap bitmap;
|
|
bitmap.allocPixels(SkImageInfo::MakeN32Premul(60, 60));
|
|
SkCanvas bitCanvas(bitmap);
|
|
SkPaint paint;
|
|
SkColor gray = 0xFF000000;
|
|
int left = 0;
|
|
for (auto right: { center.fLeft, center.fRight, bitmap.width() } ) {
|
|
int top = 0;
|
|
for (auto bottom: { center.fTop, center.fBottom, bitmap.height() } ) {
|
|
paint.setColor(gray);
|
|
bitCanvas.drawIRect(SkIRect::MakeLTRB(left, top, right, bottom), paint);
|
|
gray += 0x001f1f1f;
|
|
top = bottom;
|
|
}
|
|
left = right;
|
|
}
|
|
sk_sp<SkImage> image = SkImage::MakeFromBitmap(bitmap);
|
|
for (auto dest: { 20, 30, 40, 60, 90 } ) {
|
|
canvas->drawImageNine(image, center, SkRect::MakeWH(dest, 110 - dest), nullptr);
|
|
canvas->translate(dest + 4, 0);
|
|
}
|
|
}
|
|
##
|
|
|
|
#SeeAlso drawImage drawBitmapNine drawImageLattice drawImageRect
|
|
|
|
##
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
#Method void drawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar top,
|
|
const SkPaint* paint = nullptr)
|
|
#In Draw_Image
|
|
#In Draw
|
|
#Line # draws Bitmap at (x, y) position ##
|
|
#Populate
|
|
|
|
#Example
|
|
#Height 64
|
|
void draw(SkCanvas* canvas) {
|
|
uint8_t pixels[][8] = { { 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00},
|
|
{ 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00},
|
|
{ 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00},
|
|
{ 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF},
|
|
{ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
|
|
{ 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00},
|
|
{ 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0x00},
|
|
{ 0xFF, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0xFF} };
|
|
SkBitmap bitmap;
|
|
bitmap.installPixels(SkImageInfo::MakeA8(8, 8),
|
|
(void*) pixels, sizeof(pixels[0]));
|
|
SkPaint paint;
|
|
canvas->scale(4, 4);
|
|
for (auto color : { SK_ColorRED, SK_ColorBLUE, 0xFF007F00} ) {
|
|
paint.setColor(color);
|
|
canvas->drawBitmap(bitmap, 0, 0, &paint);
|
|
canvas->translate(12, 0);
|
|
}
|
|
}
|
|
##
|
|
|
|
#SeeAlso drawImage drawBitmapLattice drawBitmapNine drawBitmapRect SkBitmap::readPixels SkBitmap::writePixels
|
|
|
|
##
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
#Method void drawBitmapRect(const SkBitmap& bitmap, const SkRect& src, const SkRect& dst,
|
|
const SkPaint* paint, SrcRectConstraint constraint = kStrict_SrcRectConstraint)
|
|
#In Draw_Image
|
|
#In Draw
|
|
#Line # draws Bitmap, source Rect to destination Rect ##
|
|
#Populate
|
|
|
|
#Example
|
|
#Height 64
|
|
void draw(SkCanvas* canvas) {
|
|
uint8_t pixels[][8] = { { 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00},
|
|
{ 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00},
|
|
{ 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00},
|
|
{ 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF},
|
|
{ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
|
|
{ 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00},
|
|
{ 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00},
|
|
{ 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00} };
|
|
SkBitmap bitmap;
|
|
bitmap.installPixels(SkImageInfo::MakeA8(8, 8),
|
|
(void*) pixels, sizeof(pixels[0]));
|
|
SkPaint paint;
|
|
paint.setMaskFilter(SkMaskFilter::MakeBlur(kSolid_SkBlurStyle, 6));
|
|
for (auto color : { SK_ColorRED, SK_ColorBLUE, 0xFF007F00} ) {
|
|
paint.setColor(color);
|
|
canvas->drawBitmapRect(bitmap, SkRect::MakeWH(8, 8), SkRect::MakeWH(32, 32), &paint);
|
|
canvas->translate(48, 0);
|
|
}
|
|
}
|
|
##
|
|
|
|
#SeeAlso drawImageRect drawBitmap drawBitmapLattice drawBitmapNine
|
|
|
|
##
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
#Method void drawBitmapRect(const SkBitmap& bitmap, const SkIRect& isrc, const SkRect& dst,
|
|
const SkPaint* paint, SrcRectConstraint constraint = kStrict_SrcRectConstraint)
|
|
#In Draw_Image
|
|
#In Draw
|
|
#Populate
|
|
|
|
#Example
|
|
#Height 64
|
|
void draw(SkCanvas* canvas) {
|
|
uint8_t pixels[][8] = { { 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00},
|
|
{ 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00},
|
|
{ 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0xFF},
|
|
{ 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0xFF},
|
|
{ 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF},
|
|
{ 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF},
|
|
{ 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00},
|
|
{ 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00} };
|
|
SkBitmap bitmap;
|
|
bitmap.installPixels(SkImageInfo::MakeA8(8, 8),
|
|
(void*) pixels, sizeof(pixels[0]));
|
|
SkPaint paint;
|
|
paint.setFilterQuality(kHigh_SkFilterQuality);
|
|
for (auto color : { SK_ColorRED, SK_ColorBLUE, 0xFF007F00, 0xFF7f007f} ) {
|
|
paint.setColor(color);
|
|
canvas->drawBitmapRect(bitmap, SkIRect::MakeWH(8, 8), SkRect::MakeWH(32, 32), &paint);
|
|
canvas->translate(48.25f, 0);
|
|
}
|
|
}
|
|
##
|
|
|
|
#SeeAlso drawImageRect drawBitmap drawBitmapLattice drawBitmapNine
|
|
|
|
##
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
#Method void drawBitmapRect(const SkBitmap& bitmap, const SkRect& dst, const SkPaint* paint,
|
|
SrcRectConstraint constraint = kStrict_SrcRectConstraint)
|
|
#In Draw_Image
|
|
#In Draw
|
|
#Populate
|
|
|
|
#Example
|
|
#Height 64
|
|
void draw(SkCanvas* canvas) {
|
|
uint32_t pixels[][2] = { { 0x00000000, 0x55550000},
|
|
{ 0xAAAA0000, 0xFFFF0000} };
|
|
SkBitmap bitmap;
|
|
bitmap.installPixels(SkImageInfo::MakeN32Premul(2, 2),
|
|
(void*) pixels, sizeof(pixels[0]));
|
|
SkPaint paint;
|
|
canvas->scale(4, 4);
|
|
for (auto color : { SK_ColorRED, SK_ColorBLUE, SK_ColorGREEN } ) {
|
|
paint.setColorFilter(SkColorFilter::MakeModeFilter(color, SkBlendMode::kPlus));
|
|
canvas->drawBitmapRect(bitmap, SkRect::MakeWH(8, 8), &paint);
|
|
canvas->translate(8, 0);
|
|
}
|
|
}
|
|
##
|
|
|
|
#SeeAlso drawImageRect drawBitmap drawBitmapLattice drawBitmapNine
|
|
|
|
##
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
#PhraseDef paint_as_used_by_draw_lattice_or_draw_nine(bitmap_or_image)
|
|
If Paint paint is supplied, apply Color_Filter, Color_Alpha, Image_Filter,
|
|
Blend_Mode, and Draw_Looper. If #bitmap_or_image# is kAlpha_8_SkColorType, apply Shader.
|
|
If paint contains Mask_Filter, generate mask from #bitmap_or_image# bounds. If paint
|
|
Filter_Quality set to kNone_SkFilterQuality, disable pixel filtering. For all
|
|
other values of paint Filter_Quality, use kLow_SkFilterQuality to filter pixels.
|
|
Any SkMaskFilter on paint is ignored as is paint Anti_Aliasing state.
|
|
##
|
|
|
|
#Method void drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
|
|
const SkPaint* paint = nullptr)
|
|
#In Draw_Image
|
|
#In Draw
|
|
#Line # draws Nine_Patch Bitmap ##
|
|
|
|
Draws Bitmap bitmap stretched proportionally to fit into Rect dst.
|
|
IRect center divides the bitmap into nine sections: four sides, four corners,
|
|
and the center. Corners are not scaled, or scaled down proportionately if their
|
|
sides are larger than dst; center and four sides are scaled to fit remaining
|
|
space, if any.
|
|
|
|
Additionally transform draw using Clip, Matrix, and optional Paint paint.
|
|
|
|
#paint_as_used_by_draw_lattice_or_draw_nine(bitmap)#
|
|
|
|
If generated mask extends beyond bitmap bounds, replicate bitmap edge colors,
|
|
just as Shader made from SkShader::MakeBitmapShader with
|
|
SkShader::kClamp_TileMode set replicates the bitmap edge color when it samples
|
|
outside of its bounds.
|
|
|
|
#Param bitmap Bitmap containing pixels, dimensions, and format ##
|
|
#Param center IRect edge of image corners and sides ##
|
|
#Param dst destination Rect of image to draw to ##
|
|
#Param paint Paint containing Blend_Mode, Color_Filter, Image_Filter,
|
|
and so on; or nullptr
|
|
##
|
|
|
|
#Example
|
|
#Height 128
|
|
#Description
|
|
The two leftmost bitmap draws has four corners and sides to the left and right of center.
|
|
The leftmost bitmap draw scales the width of corners proportionately to fit.
|
|
The third and fourth draw corners are not scaled; the sides and center are scaled to
|
|
fill the remaining space.
|
|
The rightmost bitmap draw has four corners scaled vertically to fit, and uses sides above
|
|
and below center to fill the remaining space.
|
|
##
|
|
void draw(SkCanvas* canvas) {
|
|
SkIRect center = { 20, 10, 50, 40 };
|
|
SkBitmap bitmap;
|
|
bitmap.allocPixels(SkImageInfo::MakeN32Premul(60, 60));
|
|
SkCanvas bitCanvas(bitmap);
|
|
SkPaint paint;
|
|
SkColor gray = 0xFF000000;
|
|
int left = 0;
|
|
for (auto right: { center.fLeft, center.fRight, bitmap.width() } ) {
|
|
int top = 0;
|
|
for (auto bottom: { center.fTop, center.fBottom, bitmap.height() } ) {
|
|
paint.setColor(gray);
|
|
bitCanvas.drawIRect(SkIRect::MakeLTRB(left, top, right, bottom), paint);
|
|
gray += 0x001f1f1f;
|
|
top = bottom;
|
|
}
|
|
left = right;
|
|
}
|
|
for (auto dest: { 20, 30, 40, 60, 90 } ) {
|
|
canvas->drawBitmapNine(bitmap, center, SkRect::MakeWH(dest, 110 - dest), nullptr);
|
|
canvas->translate(dest + 4, 0);
|
|
}
|
|
}
|
|
##
|
|
|
|
#SeeAlso drawImageNine drawBitmap drawBitmapLattice drawBitmapRect
|
|
|
|
##
|
|
|
|
# ------------------------------------------------------------------------------
|
|
#Subtopic Lattice
|
|
#Line # divides Bitmap or Image into a rectangular grid ##
|
|
|
|
#Struct Lattice
|
|
#Line # divides Bitmap or Image into a rectangular grid ##
|
|
|
|
#Code
|
|
#Populate
|
|
##
|
|
|
|
Lattice divides Bitmap or Image into a rectangular grid.
|
|
Grid entries on even columns and even rows are fixed; these entries are
|
|
always drawn at their original size if the destination is large enough.
|
|
If the destination side is too small to hold the fixed entries, all fixed
|
|
entries are proportionately scaled down to fit.
|
|
The grid entries not on even columns and rows are scaled to fit the
|
|
remaining space, if any.
|
|
|
|
#Enum RectType
|
|
#Line # optional setting per rectangular grid entry ##
|
|
#Code
|
|
#Populate
|
|
##
|
|
|
|
Optional setting per rectangular grid entry to make it transparent,
|
|
or to fill the grid entry with a color.
|
|
|
|
#Const kDefault 0
|
|
#Line # draws Bitmap into lattice rectangle ##
|
|
##
|
|
|
|
#Const kTransparent 1
|
|
#Line # skips lattice rectangle by making it transparent ##
|
|
##
|
|
|
|
#Const kFixedColor 2
|
|
#Line # draws one of fColors into lattice rectangle ##
|
|
##
|
|
##
|
|
|
|
#Subtopic Members
|
|
##
|
|
|
|
#Member const int* fXDivs
|
|
#Line # x-axis values dividing bitmap ##
|
|
Array of x-axis values that divide the bitmap vertically.
|
|
Array entries must be unique, increasing, greater than or equal to
|
|
fBounds left edge, and less than fBounds right edge.
|
|
Set the first element to fBounds left to collapse the left column of
|
|
fixed grid entries.
|
|
##
|
|
|
|
#Member const int* fYDivs
|
|
#Line # y-axis values dividing bitmap ##
|
|
Array of y-axis values that divide the bitmap horizontally.
|
|
Array entries must be unique, increasing, greater than or equal to
|
|
fBounds top edge, and less than fBounds bottom edge.
|
|
Set the first element to fBounds top to collapse the top row of fixed
|
|
grid entries.
|
|
##
|
|
|
|
#Member const RectType* fRectTypes
|
|
#Line # array of fill types ##
|
|
Optional array of fill types, one per rectangular grid entry:
|
|
array length must be #Formula # (fXCount + 1) * (fYCount + 1) ##.
|
|
|
|
Each RectType is one of: kDefault, kTransparent, kFixedColor.
|
|
|
|
Array entries correspond to the rectangular grid entries, ascending
|
|
left to right and then top to bottom.
|
|
##
|
|
|
|
#Member int fXCount
|
|
#Line # number of x-coordinates ##
|
|
Number of entries in fXDivs array; one less than the number of
|
|
horizontal divisions.
|
|
##
|
|
|
|
#Member int fYCount
|
|
#Line # number of y-coordinates ##
|
|
Number of entries in fYDivs array; one less than the number of vertical
|
|
divisions.
|
|
##
|
|
|
|
#Member const SkIRect* fBounds
|
|
#Line # source bounds to draw from ##
|
|
Optional subset IRect source to draw from.
|
|
If nullptr, source bounds is dimensions of Bitmap or Image.
|
|
##
|
|
|
|
#Member const SkColor* fColors
|
|
#Line # array of colors ##
|
|
Optional array of colors, one per rectangular grid entry.
|
|
Array length must be #Formula # (fXCount + 1) * (fYCount + 1) ##.
|
|
|
|
Array entries correspond to the rectangular grid entries, ascending
|
|
left to right, then top to bottom.
|
|
##
|
|
|
|
#Struct Lattice ##
|
|
|
|
#Method void drawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice, const SkRect& dst,
|
|
const SkPaint* paint = nullptr)
|
|
#In Draw_Image
|
|
#In Draw
|
|
#Line # draws proportionally stretched Bitmap ##
|
|
|
|
Draws Bitmap bitmap stretched proportionally to fit into Rect dst.
|
|
|
|
Lattice lattice divides bitmap into a rectangular grid.
|
|
Each intersection of an even-numbered row and column is fixed; like the corners
|
|
of drawBitmapNine, fixed lattice elements never scale larger than their initial
|
|
size and shrink proportionately when all fixed elements exceed the bitmap
|
|
dimension. All other grid elements scale to fill the available space, if any.
|
|
|
|
Additionally transform draw using Clip, Matrix, and optional Paint paint.
|
|
|
|
#paint_as_used_by_draw_lattice_or_draw_nine(bitmap)#
|
|
|
|
If generated mask extends beyond bitmap bounds, replicate bitmap edge colors,
|
|
just as Shader made from SkShader::MakeBitmapShader with
|
|
SkShader::kClamp_TileMode set replicates the bitmap edge color when it samples
|
|
outside of its bounds.
|
|
|
|
#Param bitmap Bitmap containing pixels, dimensions, and format ##
|
|
#Param lattice division of bitmap into fixed and variable rectangles ##
|
|
#Param dst destination Rect of image to draw to ##
|
|
#Param paint Paint containing Blend_Mode, Color_Filter, Image_Filter,
|
|
and so on; or nullptr
|
|
##
|
|
|
|
#Example
|
|
#Height 128
|
|
#Description
|
|
The two leftmost bitmap draws has four corners and sides to the left and right of center.
|
|
The leftmost bitmap draw scales the width of corners proportionately to fit.
|
|
The third and fourth draw corners are not scaled; the sides are scaled to
|
|
fill the remaining space; the center is transparent.
|
|
The rightmost bitmap draw has four corners scaled vertically to fit, and uses sides above
|
|
and below center to fill the remaining space.
|
|
##
|
|
void draw(SkCanvas* canvas) {
|
|
SkIRect center = { 20, 10, 50, 40 };
|
|
SkBitmap bitmap;
|
|
bitmap.allocPixels(SkImageInfo::MakeN32Premul(60, 60));
|
|
SkCanvas bitCanvas(bitmap);
|
|
SkPaint paint;
|
|
SkColor gray = 0xFF000000;
|
|
int left = 0;
|
|
for (auto right: { center.fLeft, center.fRight, bitmap.width() } ) {
|
|
int top = 0;
|
|
for (auto bottom: { center.fTop, center.fBottom, bitmap.height() } ) {
|
|
paint.setColor(gray);
|
|
bitCanvas.drawIRect(SkIRect::MakeLTRB(left, top, right, bottom), paint);
|
|
gray += 0x001f1f1f;
|
|
top = bottom;
|
|
}
|
|
left = right;
|
|
}
|
|
const int xDivs[] = { center.fLeft, center.fRight };
|
|
const int yDivs[] = { center.fTop, center.fBottom };
|
|
SkCanvas::Lattice::RectType fillTypes[3][3];
|
|
memset(fillTypes, 0, sizeof(fillTypes));
|
|
fillTypes[1][1] = SkCanvas::Lattice::kTransparent;
|
|
SkColor dummy[9]; // temporary pending bug fix
|
|
SkCanvas::Lattice lattice = { xDivs, yDivs, fillTypes[0], SK_ARRAY_COUNT(xDivs),
|
|
SK_ARRAY_COUNT(yDivs), nullptr, dummy };
|
|
for (auto dest: { 20, 30, 40, 60, 90 } ) {
|
|
canvas->drawBitmapLattice(bitmap, lattice, SkRect::MakeWH(dest, 110 - dest), nullptr);
|
|
canvas->translate(dest + 4, 0);
|
|
}
|
|
}
|
|
##
|
|
|
|
#SeeAlso drawImageLattice drawBitmap drawBitmapNine Lattice
|
|
|
|
##
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
#Method void drawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
|
|
const SkPaint* paint = nullptr)
|
|
#In Draw_Image
|
|
#In Draw
|
|
#Line # draws proportionally stretched Image ##
|
|
|
|
Draws Image image stretched proportionally to fit into Rect dst.
|
|
|
|
Lattice lattice divides image into a rectangular grid.
|
|
Each intersection of an even-numbered row and column is fixed; like the corners
|
|
of drawBitmapNine, fixed lattice elements never scale larger than their initial
|
|
size and shrink proportionately when all fixed elements exceed the bitmap
|
|
dimension. All other grid elements scale to fill the available space, if any.
|
|
|
|
Additionally transform draw using Clip, Matrix, and optional Paint paint.
|
|
|
|
#paint_as_used_by_draw_lattice_or_draw_nine(image)#
|
|
|
|
If generated mask extends beyond bitmap bounds, replicate bitmap edge colors,
|
|
just as Shader made from SkShader::MakeBitmapShader with
|
|
SkShader::kClamp_TileMode set replicates the bitmap edge color when it samples
|
|
outside of its bounds.
|
|
|
|
#Param image Image containing pixels, dimensions, and format ##
|
|
#Param lattice division of bitmap into fixed and variable rectangles ##
|
|
#Param dst destination Rect of image to draw to ##
|
|
#Param paint Paint containing Blend_Mode, Color_Filter, Image_Filter,
|
|
and so on; or nullptr
|
|
##
|
|
|
|
#Example
|
|
#Height 128
|
|
#Description
|
|
The leftmost image is smaller than center; only corners are drawn, all scaled to fit.
|
|
The second image equals the size of center; only corners are drawn without scaling.
|
|
The remaining images are larger than center. All corners draw without scaling. The sides
|
|
are scaled if needed to take up the remaining space; the center is transparent.
|
|
##
|
|
void draw(SkCanvas* canvas) {
|
|
SkIRect center = { 20, 10, 50, 40 };
|
|
SkBitmap bitmap;
|
|
bitmap.allocPixels(SkImageInfo::MakeN32Premul(60, 60));
|
|
SkCanvas bitCanvas(bitmap);
|
|
SkPaint paint;
|
|
SkColor gray = 0xFF000000;
|
|
int left = 0;
|
|
for (auto right: { center.fLeft, center.fRight, bitmap.width() } ) {
|
|
int top = 0;
|
|
for (auto bottom: { center.fTop, center.fBottom, bitmap.height() } ) {
|
|
paint.setColor(gray);
|
|
bitCanvas.drawIRect(SkIRect::MakeLTRB(left, top, right, bottom), paint);
|
|
gray += 0x001f1f1f;
|
|
top = bottom;
|
|
}
|
|
left = right;
|
|
}
|
|
sk_sp<SkImage> image = SkImage::MakeFromBitmap(bitmap);
|
|
SkImage* imagePtr = image.get();
|
|
for (auto dest: { 20, 30, 40, 60, 90 } ) {
|
|
canvas->drawImageNine(imagePtr, center, SkRect::MakeWH(dest, dest), nullptr);
|
|
canvas->translate(dest + 4, 0);
|
|
}
|
|
}
|
|
##
|
|
|
|
#SeeAlso drawBitmapLattice drawImage drawImageNine Lattice
|
|
|
|
##
|
|
|
|
#Subtopic Lattice ##
|
|
|
|
#Subtopic Draw_Image ##
|
|
|
|
# ------------------------------------------------------------------------------
|
|
#Subtopic Draw_Text
|
|
#Line # draws text into Canvas ##
|
|
##
|
|
|
|
#Method void drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
|
|
const SkPaint& paint)
|
|
#In Draw_Text
|
|
#In Draw
|
|
#Line # draws text at (x, y), using font advance ##
|
|
#Populate
|
|
|
|
#Example
|
|
#Height 200
|
|
#Description
|
|
The same text is drawn varying Paint_Text_Size and varying
|
|
Matrix.
|
|
##
|
|
void draw(SkCanvas* canvas) {
|
|
SkPaint paint;
|
|
paint.setAntiAlias(true);
|
|
float textSizes[] = { 12, 18, 24, 36 };
|
|
for (auto size: textSizes ) {
|
|
paint.setTextSize(size);
|
|
canvas->drawText("Aa", 2, 10, 20, paint);
|
|
canvas->translate(0, size * 2);
|
|
}
|
|
paint.reset();
|
|
paint.setAntiAlias(true);
|
|
float yPos = 20;
|
|
for (auto size: textSizes ) {
|
|
float scale = size / 12.f;
|
|
canvas->resetMatrix();
|
|
canvas->translate(100, 0);
|
|
canvas->scale(scale, scale);
|
|
canvas->drawText("Aa", 2, 10 / scale, yPos / scale, paint);
|
|
yPos += size * 2;
|
|
}
|
|
}
|
|
##
|
|
|
|
#SeeAlso drawString drawPosText drawPosTextH drawTextBlob drawTextRSXform
|
|
|
|
##
|
|
|
|
#Method void drawString(const char* string, SkScalar x, SkScalar y, const SkPaint& paint)
|
|
#In Draw_Text
|
|
#In Draw
|
|
#Line # draws null terminated string at (x, y) using font advance ##
|
|
#Populate
|
|
|
|
#Example
|
|
#Height 48
|
|
SkPaint paint;
|
|
canvas->drawString("a small hello", 20, 20, paint);
|
|
##
|
|
|
|
#SeeAlso drawText drawPosText drawPosTextH drawTextBlob drawTextRSXform
|
|
|
|
##
|
|
|
|
#Method void drawString(const SkString& string, SkScalar x, SkScalar y, const SkPaint& paint)
|
|
#Populate
|
|
|
|
#Example
|
|
SkPaint paint;
|
|
SkString string("a small hello");
|
|
canvas->drawString(string, 20, 20, paint);
|
|
##
|
|
|
|
#SeeAlso drawText drawPosText drawPosTextH drawTextBlob drawTextRSXform
|
|
|
|
##
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
#Method void drawPosText(const void* text, size_t byteLength, const SkPoint pos[],
|
|
const SkPaint& paint)
|
|
#In Draw_Text
|
|
#In Draw
|
|
#Line # draws text at array of (x, y) positions ##
|
|
#Populate
|
|
|
|
#Example
|
|
#Height 120
|
|
void draw(SkCanvas* canvas) {
|
|
const char hello[] = "HeLLo!";
|
|
const SkPoint pos[] = { {40, 100}, {82, 95}, {115, 110}, {130, 95}, {145, 85},
|
|
{172, 100} };
|
|
SkPaint paint;
|
|
paint.setTextSize(60);
|
|
canvas->drawPosText(hello, strlen(hello), pos, paint);
|
|
}
|
|
##
|
|
|
|
#SeeAlso drawText drawPosTextH drawTextBlob drawTextRSXform
|
|
|
|
##
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
#Method void drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[], SkScalar constY,
|
|
const SkPaint& paint)
|
|
#In Draw_Text
|
|
#In Draw
|
|
#Line # draws text at x positions with common baseline ##
|
|
#Populate
|
|
|
|
#Example
|
|
#Height 40
|
|
void draw(SkCanvas* canvas) {
|
|
SkScalar xpos[] = { 20, 40, 80, 160 };
|
|
SkPaint paint;
|
|
canvas->drawPosTextH("XXXX", 4, xpos, 20, paint);
|
|
}
|
|
##
|
|
|
|
#SeeAlso drawText drawPosText drawTextBlob drawTextRSXform
|
|
|
|
##
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
#Method void drawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
|
|
const SkRect* cullRect, const SkPaint& paint)
|
|
#In Draw_Text
|
|
#In Draw
|
|
#Line # draws text with array of RSXform ##
|
|
#Populate
|
|
|
|
#Example
|
|
void draw(SkCanvas* canvas) {
|
|
const int iterations = 26;
|
|
SkRSXform transforms[iterations];
|
|
char alphabet[iterations];
|
|
SkScalar angle = 0;
|
|
SkScalar scale = 1;
|
|
for (size_t i = 0; i < SK_ARRAY_COUNT(transforms); ++i) {
|
|
const SkScalar s = SkScalarSin(angle) * scale;
|
|
const SkScalar c = SkScalarCos(angle) * scale;
|
|
transforms[i] = SkRSXform::Make(-c, -s, -s * 16, c * 16);
|
|
angle += .45;
|
|
scale += .2;
|
|
alphabet[i] = 'A' + i;
|
|
}
|
|
SkPaint paint;
|
|
canvas->translate(110, 138);
|
|
canvas->drawTextRSXform(alphabet, sizeof(alphabet), transforms, nullptr, paint);
|
|
}
|
|
##
|
|
|
|
#SeeAlso drawText drawPosText drawTextBlob
|
|
|
|
##
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
#Method void drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y, const SkPaint& paint)
|
|
#In Draw_Text
|
|
#In Draw
|
|
#Line # draws text with arrays of positions and Paint ##
|
|
Draws Text_Blob blob at (x, y), using Clip, Matrix, and Paint paint.
|
|
|
|
blob contains Glyphs, their positions, and paint attributes specific to text:
|
|
#paint_font_metrics#.
|
|
|
|
Paint_Text_Encoding must be set to SkPaint::kGlyphID_TextEncoding.
|
|
|
|
Elements of paint: Anti_Alias, Blend_Mode, Color including Color_Alpha,
|
|
Color_Filter, Paint_Dither, Draw_Looper, Mask_Filter, Path_Effect, Shader, and
|
|
Paint_Style; apply to blob. If Paint contains SkPaint::kStroke_Style:
|
|
Paint_Miter_Limit, Paint_Stroke_Cap, Paint_Stroke_Join, and Paint_Stroke_Width;
|
|
apply to Path created from blob.
|
|
|
|
#Param blob Glyphs, positions, and their paints' text size, typeface, and so on ##
|
|
#Param x horizontal offset applied to blob ##
|
|
#Param y vertical offset applied to blob ##
|
|
#Param paint blend, color, stroking, and so on, used to draw ##
|
|
|
|
#Example
|
|
#Height 120
|
|
void draw(SkCanvas* canvas) {
|
|
SkTextBlobBuilder textBlobBuilder;
|
|
const char bunny[] = "/(^x^)\\";
|
|
const int len = sizeof(bunny) - 1;
|
|
uint16_t glyphs[len];
|
|
SkPaint paint;
|
|
paint.textToGlyphs(bunny, len, glyphs);
|
|
paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
|
|
SkFont font;
|
|
int runs[] = { 3, 1, 3 };
|
|
SkPoint textPos = { 20, 100 };
|
|
int glyphIndex = 0;
|
|
for (auto runLen : runs) {
|
|
font.setSize(1 == runLen ? 20 : 50);
|
|
const SkTextBlobBuilder::RunBuffer& run =
|
|
textBlobBuilder.allocRun(font, runLen, textPos.fX, textPos.fY);
|
|
memcpy(run.glyphs, &glyphs[glyphIndex], sizeof(glyphs[0]) * runLen);
|
|
paint.setTextSize(1 == runLen ? 20 : 50);
|
|
textPos.fX += paint.measureText(&glyphs[glyphIndex], sizeof(glyphs[0]) * runLen, nullptr);
|
|
glyphIndex += runLen;
|
|
}
|
|
sk_sp<const SkTextBlob> blob = textBlobBuilder.make();
|
|
paint.reset();
|
|
canvas->drawTextBlob(blob.get(), 0, 0, paint);
|
|
}
|
|
##
|
|
|
|
#SeeAlso drawText drawPosText drawPosTextH
|
|
|
|
##
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
#Method void drawTextBlob(const sk_sp<SkTextBlob>& blob, SkScalar x, SkScalar y, const SkPaint& paint)
|
|
|
|
Draws Text_Blob blob at (x, y), using Clip, Matrix, and Paint paint.
|
|
|
|
blob contains Glyphs, their positions, and paint attributes specific to text:
|
|
#paint_font_metrics#.
|
|
|
|
Paint_Text_Encoding must be set to SkPaint::kGlyphID_TextEncoding.
|
|
|
|
Elements of paint: Path_Effect, Mask_Filter, Shader, Color_Filter,
|
|
Image_Filter, and Draw_Looper; apply to blob.
|
|
|
|
#Param blob Glyphs, positions, and their paints' text size, typeface, and so on ##
|
|
#Param x horizontal offset applied to blob ##
|
|
#Param y vertical offset applied to blob ##
|
|
#Param paint blend, color, stroking, and so on, used to draw ##
|
|
|
|
#Example
|
|
#Height 120
|
|
#Description
|
|
Paint attributes related to text, like text size, have no effect on paint passed to drawTextBlob.
|
|
##
|
|
void draw(SkCanvas* canvas) {
|
|
SkTextBlobBuilder textBlobBuilder;
|
|
SkFont font;
|
|
font.setSize(50);
|
|
const SkTextBlobBuilder::RunBuffer& run =
|
|
textBlobBuilder.allocRun(font, 1, 20, 100);
|
|
run.glyphs[0] = 20;
|
|
sk_sp<const SkTextBlob> blob = textBlobBuilder.make();
|
|
SkPaint paint;
|
|
paint.setTextSize(10);
|
|
paint.setColor(SK_ColorBLUE);
|
|
canvas->drawTextBlob(blob.get(), 0, 0, paint);
|
|
}
|
|
##
|
|
|
|
#SeeAlso drawText drawPosText drawPosTextH
|
|
|
|
##
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
#Method void drawPicture(const SkPicture* picture)
|
|
#In Draw
|
|
#Line # draws Picture using Clip and Matrix ##
|
|
#Populate
|
|
|
|
#Example
|
|
void draw(SkCanvas* canvas) {
|
|
SkPictureRecorder recorder;
|
|
SkCanvas* recordingCanvas = recorder.beginRecording(50, 50);
|
|
for (auto color : { SK_ColorRED, SK_ColorBLUE, 0xff007f00 } ) {
|
|
SkPaint paint;
|
|
paint.setColor(color);
|
|
recordingCanvas->drawRect({10, 10, 30, 40}, paint);
|
|
recordingCanvas->translate(10, 10);
|
|
recordingCanvas->scale(1.2f, 1.4f);
|
|
}
|
|
sk_sp<SkPicture> playback = recorder.finishRecordingAsPicture();
|
|
canvas->drawPicture(playback);
|
|
canvas->scale(2, 2);
|
|
canvas->translate(50, 0);
|
|
canvas->drawPicture(playback);
|
|
}
|
|
##
|
|
|
|
#SeeAlso drawDrawable SkPicture SkPicture::playback
|
|
|
|
##
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
#Method void drawPicture(const sk_sp<SkPicture>& picture)
|
|
#Populate
|
|
|
|
#Example
|
|
void draw(SkCanvas* canvas) {
|
|
SkPictureRecorder recorder;
|
|
SkCanvas* recordingCanvas = recorder.beginRecording(50, 50);
|
|
for (auto color : { SK_ColorRED, SK_ColorBLUE, 0xff007f00 } ) {
|
|
SkPaint paint;
|
|
paint.setColor(color);
|
|
recordingCanvas->drawRect({10, 10, 30, 40}, paint);
|
|
recordingCanvas->translate(10, 10);
|
|
recordingCanvas->scale(1.2f, 1.4f);
|
|
}
|
|
sk_sp<SkPicture> playback = recorder.finishRecordingAsPicture();
|
|
canvas->drawPicture(playback);
|
|
canvas->scale(2, 2);
|
|
canvas->translate(50, 0);
|
|
canvas->drawPicture(playback);
|
|
}
|
|
##
|
|
|
|
#SeeAlso drawDrawable SkPicture SkPicture::playback
|
|
|
|
##
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
#Method void drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint)
|
|
#Populate
|
|
|
|
#Example
|
|
void draw(SkCanvas* canvas) {
|
|
SkPaint paint;
|
|
SkPictureRecorder recorder;
|
|
SkCanvas* recordingCanvas = recorder.beginRecording(50, 50);
|
|
for (auto color : { SK_ColorRED, SK_ColorBLUE, 0xff007f00 } ) {
|
|
paint.setColor(color);
|
|
recordingCanvas->drawRect({10, 10, 30, 40}, paint);
|
|
recordingCanvas->translate(10, 10);
|
|
recordingCanvas->scale(1.2f, 1.4f);
|
|
}
|
|
sk_sp<SkPicture> playback = recorder.finishRecordingAsPicture();
|
|
const SkPicture* playbackPtr = playback.get();
|
|
SkMatrix matrix;
|
|
matrix.reset();
|
|
for (auto alpha : { 70, 140, 210 } ) {
|
|
paint.setAlpha(alpha);
|
|
canvas->drawPicture(playbackPtr, &matrix, &paint);
|
|
matrix.preTranslate(70, 70);
|
|
}
|
|
}
|
|
##
|
|
|
|
#SeeAlso drawDrawable SkPicture SkPicture::playback
|
|
|
|
##
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
#Method void drawPicture(const sk_sp<SkPicture>& picture, const SkMatrix* matrix, const SkPaint* paint)
|
|
#Populate
|
|
|
|
#Example
|
|
void draw(SkCanvas* canvas) {
|
|
SkPaint paint;
|
|
SkPictureRecorder recorder;
|
|
SkCanvas* recordingCanvas = recorder.beginRecording(50, 50);
|
|
for (auto color : { SK_ColorRED, SK_ColorBLUE, 0xff007f00 } ) {
|
|
paint.setColor(color);
|
|
recordingCanvas->drawRect({10, 10, 30, 40}, paint);
|
|
recordingCanvas->translate(10, 10);
|
|
recordingCanvas->scale(1.2f, 1.4f);
|
|
}
|
|
sk_sp<SkPicture> playback = recorder.finishRecordingAsPicture();
|
|
SkMatrix matrix;
|
|
matrix.reset();
|
|
for (auto alpha : { 70, 140, 210 } ) {
|
|
paint.setAlpha(alpha);
|
|
canvas->drawPicture(playback, &matrix, &paint);
|
|
matrix.preTranslate(70, 70);
|
|
}
|
|
}
|
|
##
|
|
|
|
#SeeAlso drawDrawable SkPicture SkPicture::playback
|
|
|
|
##
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
#Method void drawVertices(const SkVertices* vertices, SkBlendMode mode, const SkPaint& paint)
|
|
#In Draw
|
|
#Line # draws Vertices, a triangle mesh ##
|
|
#Populate
|
|
|
|
#Example
|
|
void draw(SkCanvas* canvas) {
|
|
SkPaint paint;
|
|
SkPoint points[] = { { 0, 0 }, { 250, 0 }, { 100, 100 }, { 0, 250 } };
|
|
SkColor colors[] = { SK_ColorRED, SK_ColorBLUE, SK_ColorYELLOW, SK_ColorCYAN };
|
|
auto vertices = SkVertices::MakeCopy(SkVertices::kTriangleFan_VertexMode,
|
|
SK_ARRAY_COUNT(points), points, nullptr, colors);
|
|
canvas->drawVertices(vertices.get(), SkBlendMode::kSrc, paint);
|
|
}
|
|
##
|
|
|
|
#SeeAlso drawPatch drawPicture
|
|
|
|
##
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
#Method void drawVertices(const sk_sp<SkVertices>& vertices, SkBlendMode mode, const SkPaint& paint)
|
|
#Populate
|
|
|
|
#Example
|
|
void draw(SkCanvas* canvas) {
|
|
SkPaint paint;
|
|
SkPoint points[] = { { 0, 0 }, { 250, 0 }, { 100, 100 }, { 0, 250 } };
|
|
SkPoint texs[] = { { 0, 0 }, { 0, 250 }, { 250, 250 }, { 250, 0 } };
|
|
SkColor colors[] = { SK_ColorRED, SK_ColorBLUE, SK_ColorYELLOW, SK_ColorCYAN };
|
|
paint.setShader(SkGradientShader::MakeLinear(points, colors, nullptr, 4,
|
|
SkShader::kClamp_TileMode));
|
|
auto vertices = SkVertices::MakeCopy(SkVertices::kTriangleFan_VertexMode,
|
|
SK_ARRAY_COUNT(points), points, texs, colors);
|
|
canvas->drawVertices(vertices, SkBlendMode::kDarken, paint);
|
|
}
|
|
##
|
|
|
|
#SeeAlso drawPatch drawPicture
|
|
|
|
##
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
#Method void drawVertices(const SkVertices* vertices, const SkVertices::Bone bones[],
|
|
int boneCount, SkBlendMode mode, const SkPaint& paint)
|
|
#Populate
|
|
|
|
#NoExample
|
|
void draw(SkCanvas* canvas) {
|
|
SkPaint paint;
|
|
SkPoint points[] = { { 0, 0 }, { 250, 0 }, { 100, 100 }, { 0, 250 } };
|
|
SkPoint texs[] = { { 0, 0 }, { 0, 250 }, { 250, 250 }, { 250, 0 } };
|
|
SkColor colors[] = { SK_ColorRED, SK_ColorBLUE, SK_ColorYELLOW, SK_ColorCYAN };
|
|
SkVertices::BoneIndices boneIndices[] = { { 0, 0, 0, 0 },
|
|
{ 1, 0, 0, 0 },
|
|
{ 2, 0, 0, 0 },
|
|
{ 3, 0, 0, 0 } };
|
|
SkVertices::BoneWeights boneWeights[] = { { 0.0f, 0.0f, 0.0f, 0.0f },
|
|
{ 1.0f, 0.0f, 0.0f, 0.0f },
|
|
{ 1.0f, 0.0f, 0.0f, 0.0f },
|
|
{ 1.0f, 0.0f, 0.0f, 0.0f } };
|
|
SkVertices::Bone bones[] = { {{ 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f }},
|
|
{{ 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 20.0f }},
|
|
{{ 1.0f, 0.0f, 0.0f, 1.0f, 50.0f, 50.0f }},
|
|
{{ 1.0f, 0.0f, 0.0f, 1.0f, 20.0f, 0.0f }} };
|
|
paint.setShader(SkGradientShader::MakeLinear(points, colors, nullptr, 4,
|
|
SkShader::kClamp_TileMode));
|
|
auto vertices = SkVertices::MakeCopy(SkVertices::kTriangleFan_VertexMode,
|
|
SK_ARRAY_COUNT(points), points, texs, colors, boneIndices, boneWeights);
|
|
canvas->drawVertices(vertices.get(), bones, SK_ARRAY_COUNT(bones), SkBlendMode::kDarken, paint);
|
|
}
|
|
##
|
|
|
|
#SeeAlso drawPatch drawPicture
|
|
|
|
##
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
#Method void drawVertices(const sk_sp<SkVertices>& vertices, const SkVertices::Bone bones[],
|
|
int boneCount, SkBlendMode mode, const SkPaint& paint)
|
|
#Populate
|
|
|
|
#NoExample
|
|
void draw(SkCanvas* canvas) {
|
|
SkPaint paint;
|
|
SkPoint points[] = { { 0, 0 }, { 250, 0 }, { 100, 100 }, { 0, 250 } };
|
|
SkPoint texs[] = { { 0, 0 }, { 0, 250 }, { 250, 250 }, { 250, 0 } };
|
|
SkColor colors[] = { SK_ColorRED, SK_ColorBLUE, SK_ColorYELLOW, SK_ColorCYAN };
|
|
SkVertices::BoneIndices boneIndices[] = { { 0, 0, 0, 0 },
|
|
{ 1, 0, 0, 0 },
|
|
{ 2, 0, 0, 0 },
|
|
{ 3, 0, 0, 0 } };
|
|
SkVertices::BoneWeights boneWeights[] = { { 0.0f, 0.0f, 0.0f, 0.0f },
|
|
{ 1.0f, 0.0f, 0.0f, 0.0f },
|
|
{ 1.0f, 0.0f, 0.0f, 0.0f },
|
|
{ 1.0f, 0.0f, 0.0f, 0.0f } };
|
|
SkVertices::Bone bones[] = { {{ 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f }},
|
|
{{ 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 20.0f }},
|
|
{{ 1.0f, 0.0f, 0.0f, 1.0f, 50.0f, 50.0f }},
|
|
{{ 1.0f, 0.0f, 0.0f, 1.0f, 20.0f, 0.0f }} };
|
|
paint.setShader(SkGradientShader::MakeLinear(points, colors, nullptr, 4,
|
|
SkShader::kClamp_TileMode));
|
|
auto vertices = SkVertices::MakeCopy(SkVertices::kTriangleFan_VertexMode,
|
|
SK_ARRAY_COUNT(points), points, texs, colors, boneIndices, boneWeights);
|
|
canvas->drawVertices(vertices, bones, SK_ARRAY_COUNT(bones), SkBlendMode::kDarken, paint);
|
|
}
|
|
##
|
|
|
|
#SeeAlso drawPatch drawPicture
|
|
|
|
##
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
#Method void drawPatch(const SkPoint cubics[12], const SkColor colors[4],
|
|
const SkPoint texCoords[4], SkBlendMode mode, const SkPaint& paint)
|
|
#In Draw
|
|
#Line # draws Coons_Patch ##
|
|
#Populate
|
|
|
|
#Example
|
|
#Image 5
|
|
void draw(SkCanvas* canvas) {
|
|
// SkBitmap source = cmbkygk;
|
|
SkPaint paint;
|
|
paint.setFilterQuality(kLow_SkFilterQuality);
|
|
paint.setAntiAlias(true);
|
|
SkPoint cubics[] = { { 3, 1 }, { 4, 2 }, { 5, 1 }, { 7, 3 },
|
|
/* { 7, 3 }, */ { 6, 4 }, { 7, 5 }, { 5, 7 },
|
|
/* { 5, 7 }, */ { 4, 6 }, { 3, 7 }, { 1, 5 },
|
|
/* { 1, 5 }, */ { 2, 4 }, { 1, 3 }, /* { 3, 1 } */ };
|
|
SkColor colors[] = { 0xbfff0000, 0xbf0000ff, 0xbfff00ff, 0xbf00ffff };
|
|
SkPoint texCoords[] = { { -30, -30 }, { 162, -30}, { 162, 162}, { -30, 162} };
|
|
paint.setShader(SkShader::MakeBitmapShader(source, SkShader::kClamp_TileMode,
|
|
SkShader::kClamp_TileMode, nullptr));
|
|
canvas->scale(15, 15);
|
|
for (auto blend : { SkBlendMode::kSrcOver, SkBlendMode::kModulate, SkBlendMode::kXor } ) {
|
|
canvas->drawPatch(cubics, colors, texCoords, blend, paint);
|
|
canvas->translate(4, 4);
|
|
}
|
|
}
|
|
##
|
|
|
|
#ToDo can patch use image filter? ##
|
|
#SeeAlso drawVertices drawPicture
|
|
|
|
##
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
#Method void drawPatch(const SkPoint cubics[12], const SkColor colors[4],
|
|
const SkPoint texCoords[4], const SkPaint& paint)
|
|
#Populate
|
|
|
|
#Example
|
|
void draw(SkCanvas* canvas) {
|
|
SkPaint paint;
|
|
paint.setAntiAlias(true);
|
|
SkPoint cubics[] = { { 3, 1 }, { 4, 2 }, { 5, 1 }, { 7, 3 },
|
|
/* { 7, 3 }, */ { 6, 4 }, { 7, 5 }, { 5, 7 },
|
|
/* { 5, 7 }, */ { 4, 6 }, { 3, 7 }, { 1, 5 },
|
|
/* { 1, 5 }, */ { 2, 4 }, { 1, 3 }, /* { 3, 1 } */ };
|
|
SkColor colors[] = { SK_ColorRED, SK_ColorBLUE, SK_ColorYELLOW, SK_ColorCYAN };
|
|
canvas->scale(30, 30);
|
|
canvas->drawPatch(cubics, colors, nullptr, paint);
|
|
SkPoint text[] = { {3,0.9f}, {4,2.5f}, {5,0.9f}, {7.5f,3.2f}, {5.5f,4.2f},
|
|
{7.5f,5.2f}, {5,7.5f}, {4,5.9f}, {3,7.5f}, {0.5f,5.2f}, {2.5f,4.2f},
|
|
{0.5f,3.2f} };
|
|
paint.setTextSize(18.f / 30);
|
|
for (int i = 0; i< 10; ++i) {
|
|
char digit = '0' + i;
|
|
canvas->drawText(&digit, 1, text[i].fX, text[i].fY, paint);
|
|
}
|
|
canvas->drawString("10", text[10].fX, text[10].fY, paint);
|
|
canvas->drawString("11", text[11].fX, text[11].fY, paint);
|
|
paint.setStyle(SkPaint::kStroke_Style);
|
|
canvas->drawPoints(SkCanvas::kPolygon_PointMode, 12, cubics, paint);
|
|
canvas->drawLine(cubics[11].fX, cubics[11].fY, cubics[0].fX, cubics[0].fY, paint);
|
|
}
|
|
##
|
|
|
|
#Example
|
|
#Image 6
|
|
void draw(SkCanvas* canvas) {
|
|
// SkBitmap source = checkerboard;
|
|
SkPaint paint;
|
|
paint.setFilterQuality(kLow_SkFilterQuality);
|
|
paint.setAntiAlias(true);
|
|
SkPoint cubics[] = { { 3, 1 }, { 4, 2 }, { 5, 1 }, { 7, 3 },
|
|
/* { 7, 3 }, */ { 6, 4 }, { 7, 5 }, { 5, 7 },
|
|
/* { 5, 7 }, */ { 4, 6 }, { 3, 7 }, { 1, 5 },
|
|
/* { 1, 5 }, */ { 2, 4 }, { 1, 3 }, /* { 3, 1 } */ };
|
|
SkPoint texCoords[] = { { 0, 0 }, { 0, 62}, { 62, 62}, { 62, 0 } };
|
|
paint.setShader(SkShader::MakeBitmapShader(source, SkShader::kClamp_TileMode,
|
|
SkShader::kClamp_TileMode, nullptr));
|
|
canvas->scale(30, 30);
|
|
canvas->drawPatch(cubics, nullptr, texCoords, paint);
|
|
}
|
|
##
|
|
|
|
#ToDo can patch use image filter? ##
|
|
#SeeAlso drawVertices drawPicture
|
|
|
|
##
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
#Method void drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
|
|
const SkColor colors[], int count, SkBlendMode mode, const SkRect* cullRect,
|
|
const SkPaint* paint)
|
|
#In Draw
|
|
#Line # draws sprites using Clip, Matrix, and Paint ##
|
|
#Populate
|
|
|
|
#Example
|
|
#Image 3
|
|
void draw(SkCanvas* canvas) {
|
|
// SkBitmap source = mandrill;
|
|
SkRSXform xforms[] = { { .5f, 0, 0, 0 }, {0, .5f, 200, 100 } };
|
|
SkRect tex[] = { { 0, 0, 250, 250 }, { 0, 0, 250, 250 } };
|
|
SkColor colors[] = { 0x7f55aa00, 0x7f3333bf };
|
|
const SkImage* imagePtr = image.get();
|
|
canvas->drawAtlas(imagePtr, xforms, tex, colors, 2, SkBlendMode::kSrcOver, nullptr, nullptr);
|
|
}
|
|
##
|
|
|
|
#SeeAlso drawBitmap drawImage
|
|
|
|
##
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
#Method void drawAtlas(const sk_sp<SkImage>& atlas, const SkRSXform xform[], const SkRect tex[],
|
|
const SkColor colors[], int count, SkBlendMode mode, const SkRect* cullRect,
|
|
const SkPaint* paint)
|
|
#Populate
|
|
|
|
#Example
|
|
#Image 3
|
|
void draw(SkCanvas* canvas) {
|
|
// SkBitmap source = mandrill;
|
|
SkRSXform xforms[] = { { .5f, 0, 0, 0 }, {0, .5f, 200, 100 } };
|
|
SkRect tex[] = { { 0, 0, 250, 250 }, { 0, 0, 250, 250 } };
|
|
SkColor colors[] = { 0x7f55aa00, 0x7f3333bf };
|
|
SkPaint paint;
|
|
paint.setAlpha(127);
|
|
canvas->drawAtlas(image, xforms, tex, colors, 2, SkBlendMode::kPlus, nullptr, &paint);
|
|
}
|
|
##
|
|
|
|
#ToDo bug in example on cpu side, gpu looks ok ##
|
|
|
|
#SeeAlso drawBitmap drawImage
|
|
|
|
##
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
#Method void drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[], int count,
|
|
const SkRect* cullRect, const SkPaint* paint)
|
|
#Populate
|
|
|
|
#Example
|
|
#Image 3
|
|
void draw(SkCanvas* canvas) {
|
|
// sk_sp<SkImage> image = mandrill;
|
|
SkRSXform xforms[] = { { .5f, 0, 0, 0 }, {0, .5f, 200, 100 } };
|
|
SkRect tex[] = { { 0, 0, 250, 250 }, { 0, 0, 250, 250 } };
|
|
const SkImage* imagePtr = image.get();
|
|
canvas->drawAtlas(imagePtr, xforms, tex, 2, nullptr, nullptr);
|
|
}
|
|
##
|
|
|
|
#SeeAlso drawBitmap drawImage
|
|
|
|
##
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
#Method void drawAtlas(const sk_sp<SkImage>& atlas, const SkRSXform xform[], const SkRect tex[],
|
|
int count, const SkRect* cullRect, const SkPaint* paint)
|
|
#Populate
|
|
|
|
#Example
|
|
#Image 3
|
|
void draw(SkCanvas* canvas) {
|
|
// sk_sp<SkImage> image = mandrill;
|
|
SkRSXform xforms[] = { { 1, 0, 0, 0 }, {0, 1, 300, 100 } };
|
|
SkRect tex[] = { { 0, 0, 200, 200 }, { 200, 0, 400, 200 } };
|
|
canvas->drawAtlas(image, xforms, tex, 2, nullptr, nullptr);
|
|
}
|
|
##
|
|
|
|
#SeeAlso drawBitmap drawImage
|
|
|
|
##
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
#Method void drawDrawable(SkDrawable* drawable, const SkMatrix* matrix = nullptr)
|
|
#In Draw
|
|
#Line # draws Drawable, encapsulated drawing commands ##
|
|
#Populate
|
|
|
|
#Example
|
|
#Height 100
|
|
#Function
|
|
struct MyDrawable : public SkDrawable {
|
|
SkRect onGetBounds() override { return SkRect::MakeWH(50, 100); }
|
|
|
|
void onDraw(SkCanvas* canvas) override {
|
|
SkPath path;
|
|
path.conicTo(10, 90, 50, 90, 0.9f);
|
|
SkPaint paint;
|
|
paint.setColor(SK_ColorBLUE);
|
|
canvas->drawRect(path.getBounds(), paint);
|
|
paint.setAntiAlias(true);
|
|
paint.setColor(SK_ColorWHITE);
|
|
canvas->drawPath(path, paint);
|
|
}
|
|
};
|
|
|
|
#Function ##
|
|
void draw(SkCanvas* canvas) {
|
|
sk_sp<SkDrawable> drawable(new MyDrawable);
|
|
SkMatrix matrix;
|
|
matrix.setTranslate(10, 10);
|
|
canvas->drawDrawable(drawable.get(), &matrix);
|
|
}
|
|
##
|
|
|
|
#SeeAlso SkDrawable drawPicture
|
|
|
|
##
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
#Method void drawDrawable(SkDrawable* drawable, SkScalar x, SkScalar y)
|
|
#Populate
|
|
|
|
#Example
|
|
#Height 100
|
|
#Function
|
|
struct MyDrawable : public SkDrawable {
|
|
SkRect onGetBounds() override { return SkRect::MakeWH(50, 100); }
|
|
|
|
void onDraw(SkCanvas* canvas) override {
|
|
SkPath path;
|
|
path.conicTo(10, 90, 50, 90, 0.9f);
|
|
SkPaint paint;
|
|
paint.setColor(SK_ColorBLUE);
|
|
canvas->drawRect(path.getBounds(), paint);
|
|
paint.setAntiAlias(true);
|
|
paint.setColor(SK_ColorWHITE);
|
|
canvas->drawPath(path, paint);
|
|
}
|
|
};
|
|
|
|
#Function ##
|
|
void draw(SkCanvas* canvas) {
|
|
sk_sp<SkDrawable> drawable(new MyDrawable);
|
|
canvas->drawDrawable(drawable.get(), 10, 10);
|
|
}
|
|
##
|
|
|
|
#SeeAlso SkDrawable drawPicture
|
|
|
|
##
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
#Method void drawAnnotation(const SkRect& rect, const char key[], SkData* value)
|
|
#In Draw
|
|
#In Utility
|
|
#Line # associates a Rect with a key-value pair ##
|
|
#Populate
|
|
|
|
#Example
|
|
#Height 1
|
|
const char text[] = "Click this link!";
|
|
SkRect bounds;
|
|
SkPaint paint;
|
|
paint.setTextSize(40);
|
|
(void)paint.measureText(text, strlen(text), &bounds);
|
|
const char url[] = "https://www.google.com/";
|
|
sk_sp<SkData> urlData(SkData::MakeWithCString(url));
|
|
canvas->drawAnnotation(bounds, "url_key", urlData.get());
|
|
##
|
|
|
|
#SeeAlso SkPicture SkDocument
|
|
|
|
##
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
#Method void drawAnnotation(const SkRect& rect, const char key[], const sk_sp<SkData>& value)
|
|
#Populate
|
|
|
|
#Example
|
|
#Height 1
|
|
const char text[] = "Click this link!";
|
|
SkRect bounds;
|
|
SkPaint paint;
|
|
paint.setTextSize(40);
|
|
(void)paint.measureText(text, strlen(text), &bounds);
|
|
const char url[] = "https://www.google.com/";
|
|
sk_sp<SkData> urlData(SkData::MakeWithCString(url));
|
|
canvas->drawAnnotation(bounds, "url_key", urlData.get());
|
|
##
|
|
|
|
#SeeAlso SkPicture SkDocument
|
|
|
|
##
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
#Method virtual bool isClipEmpty() const
|
|
#In Property
|
|
#Line # returns if Clip is empty ##
|
|
#Populate
|
|
|
|
#Example
|
|
void draw(SkCanvas* canvas) {
|
|
SkDebugf("clip is%s empty\n", canvas->isClipEmpty() ? "" : " not");
|
|
SkPath path;
|
|
canvas->clipPath(path);
|
|
SkDebugf("clip is%s empty\n", canvas->isClipEmpty() ? "" : " not");
|
|
}
|
|
#StdOut
|
|
clip is not empty
|
|
clip is empty
|
|
##
|
|
##
|
|
|
|
#SeeAlso isClipRect getLocalClipBounds getDeviceClipBounds
|
|
|
|
##
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
#Method virtual bool isClipRect() const
|
|
#In Property
|
|
#Line # returns if Clip is Rect and not empty ##
|
|
#Populate
|
|
|
|
#Example
|
|
void draw(SkCanvas* canvas) {
|
|
SkDebugf("clip is%s rect\n", canvas->isClipRect() ? "" : " not");
|
|
canvas->clipRect({0, 0, 0, 0});
|
|
SkDebugf("clip is%s rect\n", canvas->isClipRect() ? "" : " not");
|
|
}
|
|
#StdOut
|
|
clip is rect
|
|
clip is not rect
|
|
##
|
|
##
|
|
|
|
#SeeAlso isClipEmpty getLocalClipBounds getDeviceClipBounds
|
|
|
|
##
|
|
|
|
#Class SkCanvas ##
|
|
|
|
#Topic Canvas ##
|