зеркало из https://github.com/mozilla/moz-skia.git
Documentation: SkCanvas API
NOTRY=true DOCS_PREVIEW= https://skia.org/?cl=1127383010 DOCS_PREVIEW= https://skia.org/user/api?cl=1127383010 DOCS_PREVIEW= https://skia.org/user/api/skcanvas?cl=1127383010 DOCS_PREVIEW= https://skia.org/user/api/skpaint?cl=1127383010 DOCS_PREVIEW= https://skia.org/user/api/skrect?cl=1127383010 DOCS_PREVIEW= https://skia.org/user/api/skregion?cl=1127383010 DOCS_PREVIEW= https://skia.org/user/api/skmatrix?cl=1127383010 DOCS_PREVIEW= https://skia.org/user/api/canvas?cl=1127383010 Review URL: https://codereview.chromium.org/1127383010
This commit is contained in:
Родитель
4b91f768b3
Коммит
ee2a8eede9
4
Doxyfile
4
Doxyfile
|
@ -4,9 +4,11 @@
|
|||
# http://chromium-skia-gm.commondatastorage.googleapis.com/doxygen/doxygen/html/index.html
|
||||
|
||||
|
||||
PROJECT_NAME = skia
|
||||
PROJECT_NAME = Skia
|
||||
PROJECT_BRIEF = 2D Graphics Library
|
||||
|
||||
PROJECT_LOGO = https://skia.org/res/img/logo.png
|
||||
|
||||
# These lines are overridden by
|
||||
# https://chromium.googlesource.com/chromium/tools/build/+/0f611b202b0e/scripts/slave/recipe_modules/skia/resources/generate_and_upload_doxygen.py
|
||||
# but they are needed in case someone wants to generate the doxygen manually
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
{
|
||||
"dirOrder": ["sample", "quick", "special"],
|
||||
"fileOrder": ["download", "api"]
|
||||
"dirOrder": ["sample", "quick", "api", "special"],
|
||||
"fileOrder": ["download"]
|
||||
}
|
||||
|
|
|
@ -1,11 +0,0 @@
|
|||
API Overview & Doxygen Docs
|
||||
===========================
|
||||
|
||||
See navigable API Overview here:
|
||||
|
||||
[http://code.google.com/p/skia/wiki/APIOverview](http://code.google.com/p/skia/wiki/APIOverview)
|
||||
|
||||
Autogenerated Doxygen docs are here:
|
||||
|
||||
[http://chromium-skia-gm.commondatastorage.googleapis.com/doxygen/doxygen/html/index.html](http://chromium-skia-gm.commondatastorage.googleapis.com/doxygen/doxygen/html/index.html)
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"fileOrder": ["skcanvas", "skpaint", "skrect", "skregion", "skmatrix", "grcontext", "canvas"]
|
||||
}
|
|
@ -0,0 +1,250 @@
|
|||
Creating SkCanvas Objects
|
||||
=========================
|
||||
|
||||
First, read about [the SkCanvas API](skcanvas).
|
||||
|
||||
Skia has multiple backends which receive SkCanvas drawing commands,
|
||||
including:
|
||||
|
||||
- [Raster](#raster) - CPU-only.
|
||||
- [Ganesh](#ganesh) - Skia's GPU-accelerated backend.
|
||||
- [SkPDF](#skpdf) - PDF document creation.
|
||||
- [SkPicture](#skpicture) - Skia's display list format.
|
||||
- [NullCanvas](#nullcanvas) - Useful for testing only.
|
||||
- [SkXPS](#skxps) - Experimental XPS backend.
|
||||
- [SkSVG](#sksvg) - Experimental XPS backend.
|
||||
|
||||
Each backend has a unique way of creating a SkCanvas. This page gives
|
||||
an example for each:
|
||||
|
||||
<span id="raster"></span>
|
||||
Raster
|
||||
------
|
||||
|
||||
The raster backend draws to a block of memory. This memory can be
|
||||
managed by Skia or by the client.
|
||||
|
||||
The recommended way of creating a canvas for the Raster and Ganesh
|
||||
backends is to use a `SkSurface`, which is an object that manages
|
||||
the memory into which the canvas commands are drawn.
|
||||
|
||||
<!--?prettify lang=cc?-->
|
||||
|
||||
#include "SkData.h"
|
||||
#include "SkImage.h"
|
||||
#include "SkStream.h"
|
||||
#include "SkSurface.h"
|
||||
void raster(int width, int height,
|
||||
void(*draw)(SkCanvas*),
|
||||
const char* path) {
|
||||
SkAutoTUnref<SkSurface> rasterSurface(
|
||||
SkSurface::NewRasterN32Premul(width, height));
|
||||
SkCanvas* rasterCanvas = rasterSurface->getCanvas();
|
||||
draw(rasterCanvas);
|
||||
SkAutoTUnref<SkImage> img(s->newImageSnapshot());
|
||||
if (!img) { return; }
|
||||
SkAutoTUnref<SkData> png(img->encode());
|
||||
if (!png) { return; }
|
||||
SkFILEWStream out(path);
|
||||
(void)out.write(png->data(), png->size());
|
||||
}
|
||||
|
||||
Alternatively, we could have specified the memory for the surface
|
||||
explicitly, instead of asking Skia to manage it.
|
||||
|
||||
<!--?prettify lang=cc?-->
|
||||
|
||||
std::vector<char> raster_direct(int width, int height,
|
||||
void(*draw)(SkCanvas*)) {
|
||||
SkImageInfo info = SkImageInfo::MakeN32(width, height);
|
||||
size_t rowBytes = info.minRowBytes();
|
||||
size_t size = info.getSafeSize(rowBytes);
|
||||
std::vector<char> pixelMemory(size); // allocate memory
|
||||
SkAutoTUnref<SkSurface> surface(
|
||||
SkSurface::NewRasterDirect(
|
||||
info, &pixelMemory[0], rowBytes));
|
||||
SkCanvas* canvas = surface.getCanvas();
|
||||
draw(canvas);
|
||||
return std::move(pixelMemory);
|
||||
}
|
||||
|
||||
<span id="ganesh"></span>
|
||||
Ganesh
|
||||
------
|
||||
|
||||
Ganesh Surfaces must have a `GrContext` object which manages the
|
||||
GPU context, and related caches for textures and fonts. In this
|
||||
example, we use a `GrContextFactory` to create a context.
|
||||
|
||||
<!--?prettify lang=cc?-->
|
||||
|
||||
#include "GrContextFactory.h"
|
||||
#include "SkData.h"
|
||||
#include "SkImage.h"
|
||||
#include "SkStream.h"
|
||||
#include "SkSurface.h"
|
||||
void ganesh(int width, int height,
|
||||
void(*draw)(SkCanvas*),
|
||||
const char* path) {
|
||||
GrContextFactory grFactory;
|
||||
GrContext* context = grFactory.get(GrContextFactory::kNative_GLContextType);
|
||||
SkImageInfo info = SkImageInfo:: MakeN32Premul(width, height);
|
||||
SkAutoTUnref<SkSurface> gpuSurface(
|
||||
SkSurface::NewRenderTarget(context, SkSurface::kNo_Budgeted, info));
|
||||
if (!gpuSurface) {
|
||||
SkDebugf("SkSurface::NewRenderTarget returned null\n");
|
||||
return;
|
||||
}
|
||||
SkCanvas* gpuCanvas = gpuSurface->getCanvas();
|
||||
draw(gpuCanvas);
|
||||
SkAutoTUnref<SkImage> img(s->newImageSnapshot());
|
||||
if (!img) { return; }
|
||||
SkAutoTUnref<SkData> png(img->encode());
|
||||
if (!png) { return; }
|
||||
SkFILEWStream out(path);
|
||||
(void)out.write(png->data(), png->size());
|
||||
}
|
||||
|
||||
<span id="skpdf"></span>
|
||||
SkPDF
|
||||
-----
|
||||
|
||||
The SkPDF backend uses `SkDocument` instead of `SkSurface`, since
|
||||
a document must include multiple pages.
|
||||
|
||||
<!--?prettify lang=cc?-->
|
||||
|
||||
#include "SkDocument.h"
|
||||
#include "SkStream.h"
|
||||
void skpdf(int width, int height,
|
||||
void(*draw)(SkCanvas*),
|
||||
const char* path) {
|
||||
SkFILEWStream pdfStream(path);
|
||||
SkAutoTUnref<SkDocument> pdfDoc(SkDocument::CreatePDF(&pdfStream));
|
||||
SkCanvas* pdfCanvas = pdfDoc->beginPage(SkIntToScalar(width),
|
||||
SkIntToScalar(height));
|
||||
draw(pdfCanvas);
|
||||
pdfDoc->close();
|
||||
}
|
||||
|
||||
<span id="skpicture"></span>
|
||||
SkPicture
|
||||
---------
|
||||
|
||||
The SkPicture backend uses SkPictureRecorder instead of SkSurface.
|
||||
|
||||
<!--?prettify lang=cc?-->
|
||||
|
||||
#include "SkPictureRecorder"
|
||||
#include "SkPicture"
|
||||
#include "SkStream.h"
|
||||
void picture(int width, int height,
|
||||
void(*draw)(SkCanvas*),
|
||||
const char* path) {
|
||||
SkPictureRecorder recorder;
|
||||
SkCanvas* recordingCanvas = recorder.beginRecording(SkIntToScalar(width),
|
||||
SkIntToScalar(height));
|
||||
draw(recordingCanvas);
|
||||
SkAutoTUnref<SkPicture> picture(recorder.endRecordingAsPicture());
|
||||
SkFILEWStream skpStream(path);
|
||||
// Open SKP files with `SampleApp --picture SKP_FILE`
|
||||
picture->serialize(&skpStream);
|
||||
}
|
||||
|
||||
<span id="nullcanvas"></span>
|
||||
NullCanvas
|
||||
----------
|
||||
|
||||
The null canvas is a canvas that ignores all drawing commands and does
|
||||
nothing.
|
||||
|
||||
<!--?prettify lang=cc?-->
|
||||
|
||||
#include "SkNullCanvas.h"
|
||||
void picture(int, int, void(*draw)(SkCanvas*), const char*) {
|
||||
SkAutoTDelete<SkCanvas> nullCanvas(SkCreateNullCanvas());
|
||||
draw(nullCanvas); // NoOp
|
||||
}
|
||||
|
||||
<span id="skxps"></span>
|
||||
SkXPS
|
||||
-----
|
||||
|
||||
The (*still experimental*) SkXPS canvas writes into an XPS document.
|
||||
|
||||
<!--?prettify lang=cc?-->
|
||||
|
||||
#include "SkDocument.h"
|
||||
#include "SkStream.h"
|
||||
void skxps(int width, int height,
|
||||
void(*draw)(SkCanvas*),
|
||||
const char* path) {
|
||||
SkFILEWStream xpsStream(path);
|
||||
SkAutoTUnref<SkDocument> xpsDoc(SkDocument::CreateXPS(&pdfStream));
|
||||
SkCanvas* xpsCanvas = xpsDoc->beginPage(SkIntToScalar(width),
|
||||
SkIntToScalar(height));
|
||||
draw(xpsCanvas);
|
||||
xpsDoc->close();
|
||||
}
|
||||
|
||||
<span id="sksvg"></span>
|
||||
SkSVG
|
||||
-----
|
||||
|
||||
The (*still experimental*) SkSVG canvas writes into an SVG document.
|
||||
|
||||
<!--?prettify lang=cc?-->
|
||||
|
||||
#include "SkStream.h"
|
||||
#include "SkSVGCanvas.h"
|
||||
#include "SkXMLWriter.h"
|
||||
void sksvg(int width, int height,
|
||||
void(*draw)(SkCanvas*),
|
||||
const char* path) {
|
||||
SkFILEWStream svgStream(path);
|
||||
SkAutoTDelete<SkXMLWriter> xmlWriter(SkNEW_ARGS(SkXMLStreamWriter, (&svgStream)));
|
||||
SkAutoTUnref<SkCanvas> svgCanvas(SkSVGCanvas::Create(
|
||||
SkRect::MakeWH(SkIntToScalar(src.size().width()),
|
||||
SkIntToScalar(src.size().height())),
|
||||
xmlWriter));
|
||||
draw(svgCanvas);
|
||||
}
|
||||
|
||||
<span id="example"></span>
|
||||
Example
|
||||
-------
|
||||
|
||||
To try this code out, make a [new unit test using instructions
|
||||
here](/dev/testing/tests) and wrap these funtions together:
|
||||
|
||||
<!--?prettify lang=cc?-->
|
||||
|
||||
#include "SkCanvas.h"
|
||||
#include "SkPath.h"
|
||||
#include "Test.h"
|
||||
void example(SkCanvas* canvas) {
|
||||
const SkScalar scale = 256.0f;
|
||||
const SkScalar R = 0.45f * scale;
|
||||
const SkScalar TAU = 6.2831853f;
|
||||
SkPath path;
|
||||
for (int i = 0; i < 5; ++i) {
|
||||
SkScalar theta = 2 * i * TAU / 5;
|
||||
if (i == 0) {
|
||||
path.moveTo(R * cos(theta), R * sin(theta));
|
||||
} else {
|
||||
path.lineTo(R * cos(theta), R * sin(theta));
|
||||
}
|
||||
}
|
||||
path.close();
|
||||
SkPaint p;
|
||||
p.setAntiAlias(true);
|
||||
canvas->clear(SK_ColorWHITE);
|
||||
canvas->translate(0.5f * scale, 0.5f * scale);
|
||||
canvas->drawPath(path, p);
|
||||
}
|
||||
DEF_TEST(FourBackends, r) {
|
||||
raster( 256, 256, example, "out_raster.png" );
|
||||
ganesh( 256, 256, example, "out_ganesh.png" );
|
||||
skpdf( 256, 256, example, "out_skpdf.pdf" );
|
||||
picture(256, 256, example, "out_picture.skp");
|
||||
}
|
|
@ -0,0 +1,94 @@
|
|||
API Overview & Doxygen Docs
|
||||
===========================
|
||||
|
||||
Skia is organized around the `SkCanvas` object. It is the host for the
|
||||
"draw" calls: `drawRect`, `drawPath`, `drawText`, etc. Each of these
|
||||
has two components: the primitive being drawn (`SkRect`, `SkPath`, etc.)
|
||||
and color/style attributes (`SkPaint`).
|
||||
|
||||
<!--?prettify lang=cc?-->
|
||||
|
||||
canvas->drawRect(rect, paint);
|
||||
|
||||
The paint holds much of the state describing how the rectangle (in
|
||||
this case) is drawn: what color it is, if it is filled or stroked, how
|
||||
it should blend with what was previously drawn.
|
||||
|
||||
The canvas holds relatively little state. It points to the actual
|
||||
pixels being drawn, and it maintains a stack of matrices and
|
||||
clips. Thus in the above call, the canvas' current matrix may
|
||||
transform the coordinates of the rectangle (translation, rotation,
|
||||
skewing, perspective), and the canvas' current clip may restrict where
|
||||
on the canvas the rectangle will be drawn, but all other stylistic
|
||||
attributes of the drawing are controlled by the paint.
|
||||
|
||||
Using the SkCanvas API:
|
||||
|
||||
1. **[SkCanvas](/user/api/skcanvas)** - the drawing context.
|
||||
2. **[SkPaint](/user/api/skpaint)** - color, stroke, font, effects
|
||||
3. **[SkRect](/user/api/skrect)** - rectangles
|
||||
4. **[SkRegion](/user/api/skregion)** - set operations with rectangles and paths
|
||||
|
||||
Appendix:
|
||||
|
||||
1. **[Creating SkCanvas Objects](/user/api/canvas)**
|
||||
|
||||
Autogenerated Doxygen Documentaion
|
||||
----------------------------------
|
||||
|
||||
* [Skia Doxygen](http://chromium-skia-gm.commondatastorage.googleapis.com/doxygen/doxygen/html/index.html)
|
||||
|
||||
Here's a partial list of the more important Skia classes:
|
||||
|
||||
* [SkCanvas](http://chromium-skia-gm.commondatastorage.googleapis.com/doxygen/doxygen/html/classSkCanvas.html)
|
||||
* [SkImage](http://chromium-skia-gm.commondatastorage.googleapis.com/doxygen/doxygen/html/classSkImage.html)
|
||||
* [SkSurface](http://chromium-skia-gm.commondatastorage.googleapis.com/doxygen/doxygen/html/classSkSurface.html)
|
||||
* [SkPaint](http://chromium-skia-gm.commondatastorage.googleapis.com/doxygen/doxygen/html/classSkPaint.html)
|
||||
* [SkXfermode](http://chromium-skia-gm.commondatastorage.googleapis.com/doxygen/doxygen/html/classSkXfermode.html)
|
||||
- [SkLerpXfermode](http://chromium-skia-gm.commondatastorage.googleapis.com/doxygen/doxygen/html/classSkLerpXfermode.html)
|
||||
- [SkPixelXorXfermode](http://chromium-skia-gm.commondatastorage.googleapis.com/doxygen/doxygen/html/classSkPixelXorXfermode.html)
|
||||
* [SkShader](http://chromium-skia-gm.commondatastorage.googleapis.com/doxygen/doxygen/html/classSkShader.html)
|
||||
- [SkComposeShader](http://chromium-skia-gm.commondatastorage.googleapis.com/doxygen/doxygen/html/classSkComposeShader.html)
|
||||
- [SkPerlinNoiseShader](http://chromium-skia-gm.commondatastorage.googleapis.com/doxygen/doxygen/html/classSkPerlinNoiseShader.html)
|
||||
- [SkGradientShader](http://chromium-skia-gm.commondatastorage.googleapis.com/doxygen/doxygen/html/classSkGradientShader.html)
|
||||
- [SkTransparentShader](http://chromium-skia-gm.commondatastorage.googleapis.com/doxygen/doxygen/html/classSkTransparentShader.html)
|
||||
* [SkColorFilter](http://chromium-skia-gm.commondatastorage.googleapis.com/doxygen/doxygen/html/classSkColorFilter.html)
|
||||
- [SkColorCubeFilter](http://chromium-skia-gm.commondatastorage.googleapis.com/doxygen/doxygen/html/classSkColorCubeFilter.html)
|
||||
- [SkColorMatrixFilter](http://chromium-skia-gm.commondatastorage.googleapis.com/doxygen/doxygen/html/classSkColorMatrixFilter.html)
|
||||
- [SkLumaColorFilter](http://chromium-skia-gm.commondatastorage.googleapis.com/doxygen/doxygen/html/classSkLumaColorFilter.html)
|
||||
- [SkModeColorFilter](http://chromium-skia-gm.commondatastorage.googleapis.com/doxygen/doxygen/html/classSkModeColorFilter.html)
|
||||
* [SkPathEffect](http://chromium-skia-gm.commondatastorage.googleapis.com/doxygen/doxygen/html/classSkPathEffect.html)
|
||||
- [SkPath2DPathEffect](http://chromium-skia-gm.commondatastorage.googleapis.com/doxygen/doxygen/html/classSkPath2DPathEffect.html)
|
||||
- [SkLine2DPathEffect](http://chromium-skia-gm.commondatastorage.googleapis.com/doxygen/doxygen/html/classSkLine2DPathEffect.html)
|
||||
- [SkPath1DPathEffect](http://chromium-skia-gm.commondatastorage.googleapis.com/doxygen/doxygen/html/classSkPath1DPathEffect.html)
|
||||
- [SkArcToPathEffect](http://chromium-skia-gm.commondatastorage.googleapis.com/doxygen/doxygen/html/classSkArcToPathEffect.html)
|
||||
- [SkCornerPathEffect](http://chromium-skia-gm.commondatastorage.googleapis.com/doxygen/doxygen/html/classSkCornerPathEffect.html)
|
||||
- [SkDashPathEffect](http://chromium-skia-gm.commondatastorage.googleapis.com/doxygen/doxygen/html/classSkDashPathEffect.html)
|
||||
- [SkDiscretePathEffect](http://chromium-skia-gm.commondatastorage.googleapis.com/doxygen/doxygen/html/classSkDiscretePathEffect.html)
|
||||
- [SkComposePathEffect](http://chromium-skia-gm.commondatastorage.googleapis.com/doxygen/doxygen/html/classSkComposePathEffect.html)
|
||||
- [SkSumPathEffect](http://chromium-skia-gm.commondatastorage.googleapis.com/doxygen/doxygen/html/classSkSumPathEffect.html)
|
||||
* [SkImageFilter](http://chromium-skia-gm.commondatastorage.googleapis.com/doxygen/doxygen/html/classSkImageFilter.html)
|
||||
- [SkAlphaThresholdFilter](http://chromium-skia-gm.commondatastorage.googleapis.com/doxygen/doxygen/html/classSkAlphaThresholdFilter.html)
|
||||
- [SkBlurImageFilter](http://chromium-skia-gm.commondatastorage.googleapis.com/doxygen/doxygen/html/classSkBlurImageFilter.html)
|
||||
- [SkBitmapSource](http://chromium-skia-gm.commondatastorage.googleapis.com/doxygen/doxygen/html/classSkBitmapSource.html)
|
||||
- [SkColorFilterImageFilter](http://chromium-skia-gm.commondatastorage.googleapis.com/doxygen/doxygen/html/classSkColorFilterImageFilter.html)
|
||||
- [SkComposeImageFilter](http://chromium-skia-gm.commondatastorage.googleapis.com/doxygen/doxygen/html/classSkComposeImageFilter.html)
|
||||
- [SkDisplacementMapEffect](http://chromium-skia-gm.commondatastorage.googleapis.com/doxygen/doxygen/html/classSkDisplacementMapEffect.html)
|
||||
- [SkDownSampleImageFilter](http://chromium-skia-gm.commondatastorage.googleapis.com/doxygen/doxygen/html/classSkDownSampleImageFilter.html)
|
||||
- [SkDropShadowImageFilter](http://chromium-skia-gm.commondatastorage.googleapis.com/doxygen/doxygen/html/classSkDropShadowImageFilter.html)
|
||||
- [SkLightingImageFilter](http://chromium-skia-gm.commondatastorage.googleapis.com/doxygen/doxygen/html/classSkLightingImageFilter.html)
|
||||
- [SkMagnifierImageFilter](http://chromium-skia-gm.commondatastorage.googleapis.com/doxygen/doxygen/html/classSkMagnifierImageFilter.html)
|
||||
- [SkMatrixConvolutionImageFilter](http://chromium-skia-gm.commondatastorage.googleapis.com/doxygen/doxygen/html/classSkMatrixConvolutionImageFilter.html)
|
||||
- [SkMergeImageFilter](http://chromium-skia-gm.commondatastorage.googleapis.com/doxygen/doxygen/html/classSkMergeImageFilter.html)
|
||||
- [SkDilateImageFilter](http://chromium-skia-gm.commondatastorage.googleapis.com/doxygen/doxygen/html/classSkDilateImageFilter.html)
|
||||
- [SkErodeImageFilter](http://chromium-skia-gm.commondatastorage.googleapis.com/doxygen/doxygen/html/classSkErodeImageFilter.html)
|
||||
- [SkOffsetImageFilter](http://chromium-skia-gm.commondatastorage.googleapis.com/doxygen/doxygen/html/classSkOffsetImageFilter.html)
|
||||
- [SkPictureImageFilter](http://chromium-skia-gm.commondatastorage.googleapis.com/doxygen/doxygen/html/classSkPictureImageFilter.html)
|
||||
- [SkRectShaderImageFilter](http://chromium-skia-gm.commondatastorage.googleapis.com/doxygen/doxygen/html/classSkRectShaderImageFilter.html)
|
||||
- [SkTileImageFilter](http://chromium-skia-gm.commondatastorage.googleapis.com/doxygen/doxygen/html/classSkTileImageFilter.html)
|
||||
- [SkXfermodeImageFilter](http://chromium-skia-gm.commondatastorage.googleapis.com/doxygen/doxygen/html/classSkXfermodeImageFilter.html)
|
||||
* [SkMaskFilter](http://chromium-skia-gm.commondatastorage.googleapis.com/doxygen/doxygen/html/classSkMaskFilter.html)
|
||||
- [SkEmbossMaskFilter](http://chromium-skia-gm.commondatastorage.googleapis.com/doxygen/doxygen/html/classSkEmbossMaskFilter.html)
|
||||
- [SkTableMaskFilter](http://chromium-skia-gm.commondatastorage.googleapis.com/doxygen/doxygen/html/classSkTableMaskFilter.html)
|
||||
* [SkDrawLooper](http://chromium-skia-gm.commondatastorage.googleapis.com/doxygen/doxygen/html/classSkDrawLooper.html)
|
||||
- [SkBlurDrawLooper](http://chromium-skia-gm.commondatastorage.googleapis.com/doxygen/doxygen/html/classSkBlurDrawLooper.html)
|
|
@ -0,0 +1,132 @@
|
|||
SkCanvas
|
||||
========
|
||||
|
||||
*The drawing context*
|
||||
|
||||
<!-- Updated Mar 4, 2011 -->
|
||||
|
||||
Preview
|
||||
-------
|
||||
|
||||
Here is an example of a set of drawing commands to draw a filled
|
||||
heptagram. This function can be cut and pasted into
|
||||
[fiddle.skia.org](https://fiddle.skia.org/).
|
||||
|
||||
<!--?prettify lang=cc?-->
|
||||
|
||||
void draw(SkCanvas* canvas) {
|
||||
const SkScalar scale = 256.0f;
|
||||
const SkScalar R = 0.45f * scale;
|
||||
const SkScalar TAU = 6.2831853f;
|
||||
SkPath path;
|
||||
for (int i = 0; i < 7; ++i) {
|
||||
SkScalar theta = 3 * i * TAU / 7;
|
||||
if (i == 0) {
|
||||
path.moveTo(R * cos(theta), R * sin(theta));
|
||||
} else {
|
||||
path.lineTo(R * cos(theta), R * sin(theta));
|
||||
}
|
||||
}
|
||||
path.close();
|
||||
SkPaint p;
|
||||
p.setAntiAlias(true);
|
||||
canvas->clear(SK_ColorWHITE);
|
||||
canvas->translate(0.5f * scale, 0.5f * scale);
|
||||
canvas->drawPath(path, p);
|
||||
}
|
||||
|
||||
Details
|
||||
-------
|
||||
|
||||
SkCanvas is the drawing context for Skia. It knows where to direct the
|
||||
drawing (i.e. where the screen of offscreen pixels are), and maintains
|
||||
a stack of matrices and clips. Note however, that unlike similar
|
||||
contexts in other APIs like postscript, cairo, or awt, Skia does not
|
||||
store any other drawing attributes in the context (e.g. color, pen
|
||||
size). Rather, these are specified explicitly in each draw call, via a
|
||||
SkPaint.
|
||||
|
||||
<!--?prettify lang=cc?-->
|
||||
|
||||
void draw(SkCanvas* canvas) {
|
||||
canvas->save();
|
||||
canvas->rotate(SkIntToScalar(45));
|
||||
SkRect rect = SkRect::MakeXYWH(150, -50, 100, 100);
|
||||
SkPaint paint;
|
||||
canvas->drawRect(rect, paint);
|
||||
canvas->restore();
|
||||
}
|
||||
|
||||
The code above will draw a rectangle rotated by 45 degrees. Exactly
|
||||
what color and style the rect will be drawn in is described by the
|
||||
paint, not the canvas.
|
||||
|
||||
Check out more detailed info on [creating a SkCanvas object](canvas).
|
||||
|
||||
To begin with, we might want to erase the entire canvas. We can do
|
||||
this by drawing an enormous rectangle, but there are easier ways to do
|
||||
it.
|
||||
|
||||
<!--?prettify lang=cc?-->
|
||||
|
||||
void draw(SkCanvas* canvas) {
|
||||
SkPaint paint;
|
||||
paint.setColor(SK_ColorWHITE);
|
||||
canvas->drawPaint(paint);
|
||||
}
|
||||
|
||||
This fills the entire canvas (though respecting the current clip of
|
||||
course) with whatever color or shader (and xfermode) is specified by
|
||||
the paint. If there is a shader in the paint, then it will respect the
|
||||
current matrix on the canvas as well (see SkShader). If you just want
|
||||
to draw a color (with an optional xfermode), you can just call
|
||||
drawColor(), and save yourself having to allocate a paint.
|
||||
|
||||
<!--?prettify lang=cc?-->
|
||||
|
||||
void draw(SkCanvas* canvas) {
|
||||
canvas->drawColor(SK_ColorWHITE);
|
||||
}
|
||||
|
||||
All of the other draw APIs are similar, each one ending with a paint
|
||||
parameter.
|
||||
|
||||
<!--?prettify lang=cc?-->
|
||||
|
||||
void draw(SkCanvas* canvas) {
|
||||
SkPaint paint;
|
||||
paint.setStyle(SkPaint::kStroke_Style);
|
||||
paint.setStrokeWidth(2);
|
||||
|
||||
SkRect rect = SkRect::MakeXYWH(50, 50, 40, 60);
|
||||
canvas->drawRect(rect, paint);
|
||||
|
||||
SkRRect oval;
|
||||
oval.setOval(rect);
|
||||
oval.offset(40, 60);
|
||||
canvas->drawRRect(oval, paint);
|
||||
|
||||
canvas->drawCircle(180, 50, 25, paint);
|
||||
|
||||
rect.offset(80, 0);
|
||||
canvas->drawRoundRect(rect, 10, 10, paint);
|
||||
|
||||
SkPath path;
|
||||
path.cubicTo(768, 0, -512, 256, 256, 256);
|
||||
canvas->drawPath(path, paint);
|
||||
|
||||
canvas->drawBitmap(source, 128, 128, &paint);
|
||||
|
||||
SkRect rect2 = SkRect::MakeXYWH(0, 0, 40, 60);
|
||||
canvas->drawBitmapRect(source, rect2);
|
||||
|
||||
SkPaint paint2;
|
||||
const char text[] = "Hello, Skia!";
|
||||
canvas->drawText(text, strlen(text), 50, 25, paint2);
|
||||
}
|
||||
|
||||
In some of the calls, we pass a pointer, rather than a reference, to
|
||||
the paint. In those instances, the paint parameter may be null. In all
|
||||
other cases the paint parameter is required.
|
||||
|
||||
Next: [SkPaint](/user/api/skpaint)
|
|
@ -0,0 +1,12 @@
|
|||
SkMatrix
|
||||
========
|
||||
|
||||
*3x3 transforms*
|
||||
|
||||
<!-- Updated Mar 4, 2011 -->
|
||||
|
||||
Skia is a 2D graphics engine, but it supports a full 3x3
|
||||
transformation matrix. This allow it to draw anything (bitmaps, text,
|
||||
rectangles, paths) in perspective. SkCamera is a helper class that
|
||||
models a camera in 3D, and can be used to generate the proper matrix
|
||||
for a given 3D view of the plane.
|
|
@ -0,0 +1,102 @@
|
|||
SkPaint
|
||||
=======
|
||||
|
||||
*color, stroke, font, effects*
|
||||
|
||||
<!-- Updated Jan 17, 2013 by humper@google.com -->
|
||||
|
||||
Anytime you draw something in Skia, and want to specify what color it
|
||||
is, or how it blends with the background, or what style or font to
|
||||
draw it in, you specify those attributes in a paint.
|
||||
|
||||
Unlike `SkCanvas`, paints do not maintain an internal stack of state
|
||||
(i.e. there is no save/restore on a paint). However, paints are
|
||||
relatively light-weight, so the client may create and maintain any
|
||||
number of paint objects, each setup for a particular use. Factoring
|
||||
all of these color and stylistic attribute out of the canvas state,
|
||||
and into (multiple) paint objects, allows canvas' save/restore to be
|
||||
that much more efficient, as all they have to do is maintain the stack
|
||||
of matrix and clip settings.
|
||||
|
||||
<!--?prettify lang=cc?-->
|
||||
|
||||
SkPaint paint1, paint2, paint3;
|
||||
|
||||
paint1.setColor(0xFFFF0000:
|
||||
paint1.setStyle(SkPaint::kFill_Style);
|
||||
|
||||
paint2.setColor(0x8000FF00);
|
||||
paint2.setStyle(SkPaint::kStroke_Style);
|
||||
paint2.setStrokeWidth(SkIntToScalar(3));
|
||||
|
||||
paint3.setColor(0xFF888888);
|
||||
paint3.setTextSize(SkIntToScalar(24));
|
||||
paint3.setTextScaleX(SkFloatToScalar(0.75f));
|
||||
|
||||
|
||||
This shows three different paints, each setup to draw in a different
|
||||
style. Now the caller can intermix these paints freely, either using
|
||||
them as is, or modifying them as the drawing proceeds.
|
||||
|
||||
<!--?prettify lang=cc?-->
|
||||
|
||||
canvas->drawRect(..., paint1);
|
||||
canvas->drawRect(..., paint2);
|
||||
|
||||
paint2.setStrokeWidth(SkIntToScalar(5));
|
||||
canvas->drawOval(..., paint2);
|
||||
|
||||
canvas->drawText(..., paint3);
|
||||
paint3.setColor(0xFF0000FF);
|
||||
canvas->drawText(..., paint3);
|
||||
|
||||
|
||||
Beyond simple attributes such as color, strokes, and text values,
|
||||
paints support effects. These are subclasses of different aspects of
|
||||
the drawing pipeline, that when referenced by a paint (each of them is
|
||||
reference-counted), are called to override some part of the drawing
|
||||
pipeline.
|
||||
|
||||
For example, to draw using a gradient instead of a single color,
|
||||
assign a SkShader to the paint.
|
||||
|
||||
<!--?prettify lang=cc?-->
|
||||
|
||||
SkShader* shader = SkGradientShader::CreateLinear(...);
|
||||
paint.setShader(shader);
|
||||
shader->unref();
|
||||
|
||||
Now, anything drawn with that paint will be drawn with the gradient
|
||||
specified in the call to CreateLinear(). The shader object that is
|
||||
returned is reference-counted. Whenever any effects object, like a
|
||||
shader, is assigned to a paint, its reference-count is increased by
|
||||
the paint. To balance this, the caller in the above example calls
|
||||
unref() on the shader once it has assigned it to the paint. Now the
|
||||
paint is the only "owner" of that shader, and it will automatically
|
||||
call unref() on the shader when either the paint goes out of scope, or
|
||||
if another shader (or null) is assigned to it.
|
||||
|
||||
There are 6 types of effects that can be assigned to a paint:
|
||||
|
||||
* **SkPathEffect** - modifications to the geometry (path) before it
|
||||
generates an alpha mask (e.g. dashing)
|
||||
* **SkRasterizer** - composing custom mask layers (e.g. shadows)
|
||||
* **SkMaskFilter** - modifications to the alpha mask before it is
|
||||
colorized and drawn (e.g. blur, emboss)
|
||||
* **SkShader** - e.g. gradients (linear, radial, sweep), bitmap patterns
|
||||
(clamp, repeat, mirror)
|
||||
* **SkColorFilter** - modify the source color(s) before applying the
|
||||
xfermode (e.g. color matrix)
|
||||
* **SkXfermode** - e.g. porter-duff transfermodes, blend modes
|
||||
|
||||
Paints also hold a reference to a SkTypeface. The typeface represents
|
||||
a specific font style, to be used for measuring and drawing
|
||||
text. Speaking of which, paints are used not only for drawing text,
|
||||
but also for measuring it.
|
||||
|
||||
<!--?prettify lang=cc?-->
|
||||
|
||||
paint.measureText(...);
|
||||
paint.getTextBounds(...);
|
||||
paint.textToGlyphs(...);
|
||||
paint.getFontMetrics(...);
|
|
@ -0,0 +1,73 @@
|
|||
SkRect
|
||||
======
|
||||
|
||||
*Rectangles*
|
||||
|
||||
<!--Updated Mar 4, 2011-->
|
||||
|
||||
SkRect is basic to many drawing and measuring operations. It can be
|
||||
drawn using canvas.drawRect(), but it is also used to return the
|
||||
bounds of objects like paths and text characters. It is specified
|
||||
using SkScalar values.
|
||||
|
||||
SkIRect is the integer counter part to SkRect, but is specified using
|
||||
32bit integers.
|
||||
|
||||
<!--?prettify lang=cc?-->
|
||||
|
||||
struct SkRect {
|
||||
SkScalar fLeft;
|
||||
SkScalar fTop;
|
||||
SkScalar fRight;
|
||||
SkScalar fBottom;
|
||||
// methods
|
||||
};
|
||||
|
||||
SkRect rect = SkRect::MakeLTRB(left, top, right, bottom);
|
||||
|
||||
SkRect has the usual getters, to return width(), height(), centerX(),
|
||||
etc. It also has methods to compute unions and intersections between
|
||||
rectangles.
|
||||
|
||||
Converting between SkRect and SkIRect is asymetric. Short of overflow
|
||||
issues when SkScalar is an int, converting from SkIRect to SkRect is
|
||||
straight forward:
|
||||
|
||||
<!--?prettify lang=cc?-->
|
||||
|
||||
SkRect::set(const SkIRect&);
|
||||
|
||||
However, convert from SkRect to SkIRect needs to know how to go from
|
||||
fractional values to integers.
|
||||
|
||||
<!--?prettify lang=cc?-->
|
||||
|
||||
SkRect::round(SkIRect*) const; // Round each coordinate.
|
||||
SkRect::roundOut(SkIRect*) const; // Apply floor to left/top,
|
||||
// and ceil to right/bottom.
|
||||
|
||||
In Skia, rectangle coordinates describe the boundary of what is drawn,
|
||||
such that an empty rectangle encloses zero pixels:
|
||||
|
||||
bool SkRect::isEmpty() const { return fLeft >= fRight || fTop >= fBottom; }
|
||||
|
||||
<!--?prettify lang=cc?-->
|
||||
|
||||
SkScalar SkRect::width() const { return fRight - fLeft; }
|
||||
|
||||
SkScalar SkRect::height() const { return fBottom - fTop; }
|
||||
|
||||
bool SkRect::contains(SkScalar x, SkScalar y) const {
|
||||
return fLeft <= x && x < fRight && fTop <= y && y < fBottom;
|
||||
}
|
||||
|
||||
Thus, to draw a single pixel (assuming no matrix on the canvas), the
|
||||
rectangle should be initialized as follows:
|
||||
|
||||
<!--?prettify lang=cc?-->
|
||||
|
||||
SkRect r = SkRect::MakeXYWH(x, y, SkIntToScalar(1), SkIntToScalar(1));
|
||||
|
||||
The same conventions hold for the integer counterpart: SkIRect. This
|
||||
also dovetails with SkRegion, which has the same model for set
|
||||
membership, and which uses SkIRect.
|
|
@ -0,0 +1,111 @@
|
|||
SkRegion
|
||||
========
|
||||
|
||||
*Regions - set operations with rectangles*
|
||||
|
||||
<!-- Updated Mar 4, 2011 -->
|
||||
|
||||
Regions are a highly compressed way to represent (integer) areas. Skia
|
||||
uses them to represent (internally) the current clip on the
|
||||
canvas. Regions take their inspiration from the data type with the
|
||||
same name on the original Macintosh (thank you Bill).
|
||||
|
||||
Regions are opaque structures, but they can be queried via
|
||||
iterators. Best of all, they can be combined with other regions and
|
||||
with rectangles (which can be thought of as "simple" regions. If you
|
||||
remember Set operations from math class (intersection, union,
|
||||
difference, etc.), then you're all ready to use regions.
|
||||
|
||||
<!--?prettify lang=cc?-->
|
||||
|
||||
bool SkRegion::isEmpty();
|
||||
bool SkRegion::isRect();
|
||||
bool SkRegion::isComplex();
|
||||
|
||||
Regions can be classified into one of three types: empty, rectangular,
|
||||
or complex.
|
||||
|
||||
Empty regions are just that, empty. All empty regions are equal (using
|
||||
operator==). Compare this to rectangles (SkRect or SkIRect). Any
|
||||
rectangle with fLeft >= fRight or fTop >= fBottom is consider empty,
|
||||
but clearly there are different empty rectangles that are not equal.
|
||||
|
||||
<!--?prettify lang=cc?-->
|
||||
|
||||
SkRect a = { 0, 0, 0, 0 };
|
||||
SkRect b = { 1, 1, 1, 1 };
|
||||
|
||||
Both a and b are empty, but they are definitely not equal to each
|
||||
other. However, with regions, all empty regions are equal. If you
|
||||
query its bounds, you will always get { 0, 0, 0, 0 }. Even if you
|
||||
translate it, it will still be all zeros.
|
||||
|
||||
<!--?prettify lang=cc?-->
|
||||
|
||||
<!--?prettify lang=cc?-->
|
||||
|
||||
SkRegion a, b; // regions default to empty
|
||||
assert(a == b);
|
||||
a.offset(10, 20);
|
||||
assert(a == b);
|
||||
assert(a.getBounds() == { 0, 0, 0, 0 }); // not legal C++, but you get the point
|
||||
assert(b.getBounds() == { 0, 0, 0, 0 });
|
||||
|
||||
To initialize a region to something more interesting, use one of the
|
||||
set() methods
|
||||
|
||||
<!--?prettify lang=cc?-->
|
||||
|
||||
SkRegion a, b;
|
||||
a.setRect(10, 10, 50, 50);
|
||||
b.setRect(rect); // see SkIRect
|
||||
c.setPath(path); // see SkPath
|
||||
|
||||
This is the first step that SkCanvas performs when one of its
|
||||
clip...() methods are called. The clip data is first transformed into
|
||||
device coordinates (see SkMatrix), and then a region is build from the
|
||||
data (either a rect or a path). The final step is to combine this new
|
||||
region with the existing clip using the specified operator.
|
||||
|
||||
<!--?prettify lang=cc?-->
|
||||
|
||||
enum Op {
|
||||
kUnion_Op,
|
||||
kIntersect_Op,
|
||||
kDifference_Op,
|
||||
kXor_Op,
|
||||
kReverseDifference_Op,
|
||||
kReplace_Op
|
||||
};
|
||||
|
||||
By default, intersect op is used when a clip call is made, but the
|
||||
other operators are equally valid.
|
||||
|
||||
<!--?prettify lang=cc?-->
|
||||
|
||||
// returns true if the resulting clip is non-empty (i.e. drawing can
|
||||
// still occur)
|
||||
bool SkCanvas::clipRect(const SkRect& rect, SkRegion::Op op) {
|
||||
SkRegion rgn;
|
||||
|
||||
// peek at the CTM (current transformation matrix on the canvas)
|
||||
const SkMatrix& m = this->getTotalMatrix();
|
||||
|
||||
if (m.rectStaysRect()) { // check if a transformed rect can be
|
||||
// represented as another rect
|
||||
|
||||
SkRect deviceRect;
|
||||
m.mapRect(&deviceRect, rect);
|
||||
SkIRect intRect;
|
||||
deviceRect.round(&intRect);
|
||||
rgn.setRect(intRect);
|
||||
} else { // matrix rotates or skew (or is perspective)
|
||||
SkPath path;
|
||||
path.addRect(rect);
|
||||
path.transform(m);
|
||||
rgn.setPath(path);
|
||||
}
|
||||
|
||||
// now combine the new region with the current one, using the specified *op*
|
||||
return fCurrentClip.op(rgn, op);
|
||||
}
|
Загрузка…
Ссылка в новой задаче