Home | History | Annotate | Download | only in core
      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 
     16 SkBaseDevice::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 
     26 SkBaseDevice::~SkBaseDevice() {
     27     SkDELETE(fLeakyProperties);
     28     SkDELETE(fMetaData);
     29 }
     30 
     31 SkBaseDevice* SkBaseDevice::createCompatibleDevice(const SkImageInfo& info) {
     32     return this->onCreateDevice(info, kGeneral_Usage);
     33 }
     34 
     35 SkBaseDevice* SkBaseDevice::createCompatibleDeviceForSaveLayer(const SkImageInfo& info) {
     36     return this->onCreateDevice(info, kSaveLayer_Usage);
     37 }
     38 
     39 SkBaseDevice* SkBaseDevice::createCompatibleDeviceForImageFilter(const SkImageInfo& info) {
     40     return this->onCreateDevice(info, kImageFilter_Usage);
     41 }
     42 
     43 SkMetaData& 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 
     52 SkImageInfo SkBaseDevice::imageInfo() const {
     53     return SkImageInfo::MakeUnknown();
     54 }
     55 
     56 const SkBitmap& SkBaseDevice::accessBitmap(bool changePixels) {
     57     const SkBitmap& bitmap = this->onAccessBitmap();
     58     if (changePixels) {
     59         bitmap.notifyPixelsChanged();
     60     }
     61     return bitmap;
     62 }
     63 
     64 void SkBaseDevice::setPixelGeometry(SkPixelGeometry geo) {
     65     fLeakyProperties->fPixelGeometry = geo;
     66 }
     67 
     68 SkSurface* SkBaseDevice::newSurface(const SkImageInfo&, const SkSurfaceProps&) { return NULL; }
     69 
     70 const void* SkBaseDevice::peekPixels(SkImageInfo*, size_t*) { return NULL; }
     71 
     72 void 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 
     84 void 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 
     99 void 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 
    150 bool 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 
    164 bool 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 
    179 bool SkBaseDevice::onWritePixels(const SkImageInfo&, const void*, size_t, int, int) {
    180     return false;
    181 }
    182 
    183 bool SkBaseDevice::onReadPixels(const SkImageInfo&, void*, size_t, int x, int y) {
    184     return false;
    185 }
    186 
    187 void* 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 
    199 void* SkBaseDevice::onAccessPixels(SkImageInfo* info, size_t* rowBytes) {
    200     return NULL;
    201 }
    202 
    203 void SkBaseDevice::EXPERIMENTAL_optimize(const SkPicture* picture) {
    204     // The base class doesn't perform any analysis but derived classes may
    205 }
    206 
    207 bool 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