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->onCreateDevice(info, kGeneral_Usage); 33} 34 35SkBaseDevice* SkBaseDevice::createCompatibleDeviceForSaveLayer(const SkImageInfo& info) { 36 return this->onCreateDevice(info, kSaveLayer_Usage); 37} 38 39SkBaseDevice* SkBaseDevice::createCompatibleDeviceForImageFilter(const SkImageInfo& info) { 40 return this->onCreateDevice(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->fPixelGeometry = 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 SkMatrix localMatrix; 104 SkDraw localDraw(draw); 105 106 if (x || y) { 107 localMatrix = *draw.fMatrix; 108 localMatrix.preTranslate(x, y); 109 localDraw.fMatrix = &localMatrix; 110 111 if (paint.getShader()) { 112 // FIXME: We need to compensate for the translate above. This is suboptimal but 113 // temporary -- until we get proper derived class drawTextBlob implementations. 114 115 // TODO: pass x,y down to the other methods so they can handle the additional 116 // translate without needing to allocate a new shader. 117 SkMatrix shaderMatrix; 118 shaderMatrix.setTranslate(-x, -y); 119 SkAutoTUnref<SkShader> wrapper( 120 SkShader::CreateLocalMatrixShader(paint.getShader(), shaderMatrix)); 121 runPaint.setShader(wrapper); 122 } 123 } 124 125 SkTextBlob::RunIterator it(blob); 126 while (!it.done()) { 127 size_t textLen = it.glyphCount() * sizeof(uint16_t); 128 const SkPoint& offset = it.offset(); 129 // applyFontToPaint() always overwrites the exact same attributes, 130 // so it is safe to not re-seed the paint. 131 it.applyFontToPaint(&runPaint); 132 133 switch (it.positioning()) { 134 case SkTextBlob::kDefault_Positioning: 135 this->drawText(localDraw, it.glyphs(), textLen, offset.x(), offset.y(), runPaint); 136 break; 137 case SkTextBlob::kHorizontal_Positioning: 138 case SkTextBlob::kFull_Positioning: 139 this->drawPosText(localDraw, it.glyphs(), textLen, it.pos(), offset.y(), 140 SkTextBlob::ScalarsPerGlyph(it.positioning()), runPaint); 141 break; 142 default: 143 SkFAIL("unhandled positioning mode"); 144 } 145 146 it.next(); 147 } 148} 149 150bool SkBaseDevice::readPixels(const SkImageInfo& info, void* dstP, size_t rowBytes, int x, int y) { 151#ifdef SK_DEBUG 152 SkASSERT(info.width() > 0 && info.height() > 0); 153 SkASSERT(dstP); 154 SkASSERT(rowBytes >= info.minRowBytes()); 155 SkASSERT(x >= 0 && y >= 0); 156 157 const SkImageInfo& srcInfo = this->imageInfo(); 158 SkASSERT(x + info.width() <= srcInfo.width()); 159 SkASSERT(y + info.height() <= srcInfo.height()); 160#endif 161 return this->onReadPixels(info, dstP, rowBytes, x, y); 162} 163 164bool SkBaseDevice::writePixels(const SkImageInfo& info, const void* pixels, size_t rowBytes, 165 int x, int y) { 166#ifdef SK_DEBUG 167 SkASSERT(info.width() > 0 && info.height() > 0); 168 SkASSERT(pixels); 169 SkASSERT(rowBytes >= info.minRowBytes()); 170 SkASSERT(x >= 0 && y >= 0); 171 172 const SkImageInfo& dstInfo = this->imageInfo(); 173 SkASSERT(x + info.width() <= dstInfo.width()); 174 SkASSERT(y + info.height() <= dstInfo.height()); 175#endif 176 return this->onWritePixels(info, pixels, rowBytes, x, y); 177} 178 179bool SkBaseDevice::onWritePixels(const SkImageInfo&, const void*, size_t, int, int) { 180 return false; 181} 182 183bool SkBaseDevice::onReadPixels(const SkImageInfo&, void*, size_t, int x, int y) { 184 return false; 185} 186 187void* SkBaseDevice::accessPixels(SkImageInfo* info, size_t* rowBytes) { 188 SkImageInfo tmpInfo; 189 size_t tmpRowBytes; 190 if (NULL == info) { 191 info = &tmpInfo; 192 } 193 if (NULL == rowBytes) { 194 rowBytes = &tmpRowBytes; 195 } 196 return this->onAccessPixels(info, rowBytes); 197} 198 199void* SkBaseDevice::onAccessPixels(SkImageInfo* info, size_t* rowBytes) { 200 return NULL; 201} 202 203void SkBaseDevice::EXPERIMENTAL_optimize(const SkPicture* picture) { 204 // The base class doesn't perform any analysis but derived classes may 205} 206 207bool SkBaseDevice::EXPERIMENTAL_drawPicture(SkCanvas*, const SkPicture*, const SkMatrix*, 208 const SkPaint*) { 209 // The base class doesn't perform any accelerated picture rendering 210 return false; 211} 212