diff options
author | halcanary <halcanary@google.com> | 2015-05-19 10:21:29 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-05-19 10:21:29 -0700 |
commit | ee2a8eede9ba9efd34cd132c5abc175f9c434b7a (patch) | |
tree | f53f8309b1877fb10283a4b8994e0760d9dd6ca8 /site/user | |
parent | 4b91f768b348aa1cebeb54f3ff9331938734c242 (diff) |
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
Diffstat (limited to 'site/user')
-rw-r--r-- | site/user/METADATA | 4 | ||||
-rw-r--r-- | site/user/api.md | 11 | ||||
-rw-r--r-- | site/user/api/METADATA | 3 | ||||
-rw-r--r-- | site/user/api/canvas.md | 250 | ||||
-rw-r--r-- | site/user/api/index.md | 94 | ||||
-rw-r--r-- | site/user/api/skcanvas.md | 132 | ||||
-rw-r--r-- | site/user/api/skmatrix.md | 12 | ||||
-rw-r--r-- | site/user/api/skpaint.md | 102 | ||||
-rw-r--r-- | site/user/api/skrect.md | 73 | ||||
-rw-r--r-- | site/user/api/skregion.md | 111 |
10 files changed, 779 insertions, 13 deletions
diff --git a/site/user/METADATA b/site/user/METADATA index 5d835d962b..1735b80124 100644 --- a/site/user/METADATA +++ b/site/user/METADATA @@ -1,4 +1,4 @@ { - "dirOrder": ["sample", "quick", "special"], - "fileOrder": ["download", "api"] + "dirOrder": ["sample", "quick", "api", "special"], + "fileOrder": ["download"] } diff --git a/site/user/api.md b/site/user/api.md deleted file mode 100644 index 0b507b98cd..0000000000 --- a/site/user/api.md +++ /dev/null @@ -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) - diff --git a/site/user/api/METADATA b/site/user/api/METADATA new file mode 100644 index 0000000000..27625c5c1a --- /dev/null +++ b/site/user/api/METADATA @@ -0,0 +1,3 @@ +{ + "fileOrder": ["skcanvas", "skpaint", "skrect", "skregion", "skmatrix", "grcontext", "canvas"] +} diff --git a/site/user/api/canvas.md b/site/user/api/canvas.md new file mode 100644 index 0000000000..eacd1ccbd4 --- /dev/null +++ b/site/user/api/canvas.md @@ -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"); + } diff --git a/site/user/api/index.md b/site/user/api/index.md new file mode 100644 index 0000000000..8c578b3d59 --- /dev/null +++ b/site/user/api/index.md @@ -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) diff --git a/site/user/api/skcanvas.md b/site/user/api/skcanvas.md new file mode 100644 index 0000000000..157409da38 --- /dev/null +++ b/site/user/api/skcanvas.md @@ -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) diff --git a/site/user/api/skmatrix.md b/site/user/api/skmatrix.md new file mode 100644 index 0000000000..3048cdc19f --- /dev/null +++ b/site/user/api/skmatrix.md @@ -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. diff --git a/site/user/api/skpaint.md b/site/user/api/skpaint.md new file mode 100644 index 0000000000..fdee783d4b --- /dev/null +++ b/site/user/api/skpaint.md @@ -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(...); diff --git a/site/user/api/skrect.md b/site/user/api/skrect.md new file mode 100644 index 0000000000..c2ebef1d0f --- /dev/null +++ b/site/user/api/skrect.md @@ -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. diff --git a/site/user/api/skregion.md b/site/user/api/skregion.md new file mode 100644 index 0000000000..f4f46c951b --- /dev/null +++ b/site/user/api/skregion.md @@ -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); + } |