SkDevice.cpp revision b122ee50fb56cf6669fe1668b82c8815896e9943
1/*
2 * Copyright 2011 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "SkDevice.h"
9#include "SkDeviceProperties.h"
10#include "SkDraw.h"
11#include "SkMetaData.h"
12#include "SkPatchUtils.h"
13#include "SkShader.h"
14#include "SkTextBlob.h"
15
16SkBaseDevice::SkBaseDevice()
17    : fLeakyProperties(SkNEW_ARGS(SkDeviceProperties, (SkDeviceProperties::kLegacyLCD_InitType)))
18#ifdef SK_DEBUG
19    , fAttachedToCanvas(false)
20#endif
21{
22    fOrigin.setZero();
23    fMetaData = NULL;
24}
25
26SkBaseDevice::~SkBaseDevice() {
27    SkDELETE(fLeakyProperties);
28    SkDELETE(fMetaData);
29}
30
31SkBaseDevice* SkBaseDevice::createCompatibleDevice(const SkImageInfo& info) {
32    return this->onCreateCompatibleDevice(CreateInfo(info, kGeneral_Usage));
33}
34
35SkBaseDevice* SkBaseDevice::createCompatibleDeviceForSaveLayer(const SkImageInfo& info) {
36    return this->onCreateCompatibleDevice(CreateInfo(info, kSaveLayer_Usage));
37}
38
39SkBaseDevice* SkBaseDevice::createCompatibleDeviceForImageFilter(const SkImageInfo& info) {
40    return this->onCreateCompatibleDevice(CreateInfo(info, kImageFilter_Usage));
41}
42
43SkMetaData& SkBaseDevice::getMetaData() {
44    // metadata users are rare, so we lazily allocate it. If that changes we
45    // can decide to just make it a field in the device (rather than a ptr)
46    if (NULL == fMetaData) {
47        fMetaData = new SkMetaData;
48    }
49    return *fMetaData;
50}
51
52SkImageInfo SkBaseDevice::imageInfo() const {
53    return SkImageInfo::MakeUnknown();
54}
55
56const SkBitmap& SkBaseDevice::accessBitmap(bool changePixels) {
57    const SkBitmap& bitmap = this->onAccessBitmap();
58    if (changePixels) {
59        bitmap.notifyPixelsChanged();
60    }
61    return bitmap;
62}
63
64void SkBaseDevice::setPixelGeometry(SkPixelGeometry geo) {
65    fLeakyProperties->setPixelGeometry(geo);
66}
67
68SkSurface* SkBaseDevice::newSurface(const SkImageInfo&, const SkSurfaceProps&) { return NULL; }
69
70const void* SkBaseDevice::peekPixels(SkImageInfo*, size_t*) { return NULL; }
71
72void SkBaseDevice::drawDRRect(const SkDraw& draw, const SkRRect& outer,
73                              const SkRRect& inner, const SkPaint& paint) {
74    SkPath path;
75    path.addRRect(outer);
76    path.addRRect(inner);
77    path.setFillType(SkPath::kEvenOdd_FillType);
78
79    const SkMatrix* preMatrix = NULL;
80    const bool pathIsMutable = true;
81    this->drawPath(draw, path, paint, preMatrix, pathIsMutable);
82}
83
84void SkBaseDevice::drawPatch(const SkDraw& draw, const SkPoint cubics[12], const SkColor colors[4],
85                             const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) {
86    SkPatchUtils::VertexData data;
87
88    SkISize lod = SkPatchUtils::GetLevelOfDetail(cubics, draw.fMatrix);
89
90    // It automatically adjusts lodX and lodY in case it exceeds the number of indices.
91    // If it fails to generate the vertices, then we do not draw.
92    if (SkPatchUtils::getVertexData(&data, cubics, colors, texCoords, lod.width(), lod.height())) {
93        this->drawVertices(draw, SkCanvas::kTriangles_VertexMode, data.fVertexCount, data.fPoints,
94                           data.fTexCoords, data.fColors, xmode, data.fIndices, data.fIndexCount,
95                           paint);
96    }
97}
98
99void SkBaseDevice::drawTextBlob(const SkDraw& draw, const SkTextBlob* blob, SkScalar x, SkScalar y,
100                                const SkPaint &paint) {
101
102    SkPaint runPaint = paint;
103
104    SkTextBlob::RunIterator it(blob);
105    while (!it.done()) {
106        size_t textLen = it.glyphCount() * sizeof(uint16_t);
107        const SkPoint& offset = it.offset();
108        // applyFontToPaint() always overwrites the exact same attributes,
109        // so it is safe to not re-seed the paint.
110        it.applyFontToPaint(&runPaint);
111
112        switch (it.positioning()) {
113        case SkTextBlob::kDefault_Positioning:
114            this->drawText(draw, it.glyphs(), textLen, x + offset.x(), y + offset.y(), runPaint);
115            break;
116        case SkTextBlob::kHorizontal_Positioning:
117            this->drawPosText(draw, it.glyphs(), textLen, it.pos(), 1,
118                              SkPoint::Make(x, y + offset.y()), runPaint);
119            break;
120        case SkTextBlob::kFull_Positioning:
121            this->drawPosText(draw, it.glyphs(), textLen, it.pos(), 2,
122                              SkPoint::Make(x, y), runPaint);
123            break;
124        default:
125            SkFAIL("unhandled positioning mode");
126        }
127
128        it.next();
129    }
130}
131
132bool SkBaseDevice::readPixels(const SkImageInfo& info, void* dstP, size_t rowBytes, int x, int y) {
133#ifdef SK_DEBUG
134    SkASSERT(info.width() > 0 && info.height() > 0);
135    SkASSERT(dstP);
136    SkASSERT(rowBytes >= info.minRowBytes());
137    SkASSERT(x >= 0 && y >= 0);
138
139    const SkImageInfo& srcInfo = this->imageInfo();
140    SkASSERT(x + info.width() <= srcInfo.width());
141    SkASSERT(y + info.height() <= srcInfo.height());
142#endif
143    return this->onReadPixels(info, dstP, rowBytes, x, y);
144}
145
146bool SkBaseDevice::writePixels(const SkImageInfo& info, const void* pixels, size_t rowBytes,
147                               int x, int y) {
148#ifdef SK_DEBUG
149    SkASSERT(info.width() > 0 && info.height() > 0);
150    SkASSERT(pixels);
151    SkASSERT(rowBytes >= info.minRowBytes());
152    SkASSERT(x >= 0 && y >= 0);
153
154    const SkImageInfo& dstInfo = this->imageInfo();
155    SkASSERT(x + info.width() <= dstInfo.width());
156    SkASSERT(y + info.height() <= dstInfo.height());
157#endif
158    return this->onWritePixels(info, pixels, rowBytes, x, y);
159}
160
161bool SkBaseDevice::onWritePixels(const SkImageInfo&, const void*, size_t, int, int) {
162    return false;
163}
164
165bool SkBaseDevice::onReadPixels(const SkImageInfo&, void*, size_t, int x, int y) {
166    return false;
167}
168
169void* SkBaseDevice::accessPixels(SkImageInfo* info, size_t* rowBytes) {
170    SkImageInfo tmpInfo;
171    size_t tmpRowBytes;
172    if (NULL == info) {
173        info = &tmpInfo;
174    }
175    if (NULL == rowBytes) {
176        rowBytes = &tmpRowBytes;
177    }
178    return this->onAccessPixels(info, rowBytes);
179}
180
181void* SkBaseDevice::onAccessPixels(SkImageInfo* info, size_t* rowBytes) {
182    return NULL;
183}
184
185bool SkBaseDevice::EXPERIMENTAL_drawPicture(SkCanvas*, const SkPicture*, const SkMatrix*,
186                                            const SkPaint*) {
187    // The base class doesn't perform any accelerated picture rendering
188    return false;
189}
190