Home | History | Annotate | Download | only in hwui
      1 /*
      2  * Copyright (C) 2015 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include "SkiaCanvasProxy.h"
     18 
     19 #include <memory>
     20 
     21 #include <log/log.h>
     22 
     23 #include <SkLatticeIter.h>
     24 #include <SkPaint.h>
     25 #include <SkPatchUtils.h>
     26 #include <SkPath.h>
     27 #include <SkPixelRef.h>
     28 #include <SkRRect.h>
     29 #include <SkRSXform.h>
     30 #include <SkRect.h>
     31 #include <SkSurface.h>
     32 #include <SkTextBlobRunIterator.h>
     33 #include <SkVertices.h>
     34 #include "hwui/Bitmap.h"
     35 
     36 namespace android {
     37 namespace uirenderer {
     38 
     39 SkiaCanvasProxy::SkiaCanvasProxy(Canvas* canvas, bool filterHwuiCalls)
     40         : INHERITED(canvas->width(), canvas->height())
     41         , mCanvas(canvas)
     42         , mFilterHwuiCalls(filterHwuiCalls) {}
     43 
     44 void SkiaCanvasProxy::onDrawPaint(const SkPaint& paint) {
     45     mCanvas->drawPaint(paint);
     46 }
     47 
     48 void SkiaCanvasProxy::onDrawPoints(PointMode pointMode, size_t count, const SkPoint pts[],
     49                                    const SkPaint& paint) {
     50     if (!pts || count == 0) {
     51         return;
     52     }
     53 
     54     // convert the SkPoints into floats
     55     static_assert(sizeof(SkPoint) == sizeof(float) * 2, "SkPoint is no longer two floats");
     56     const size_t floatCount = count << 1;
     57     const float* floatArray = &pts[0].fX;
     58 
     59     switch (pointMode) {
     60         case kPoints_PointMode: {
     61             mCanvas->drawPoints(floatArray, floatCount, paint);
     62             break;
     63         }
     64         case kLines_PointMode: {
     65             mCanvas->drawLines(floatArray, floatCount, paint);
     66             break;
     67         }
     68         case kPolygon_PointMode: {
     69             SkPaint strokedPaint(paint);
     70             strokedPaint.setStyle(SkPaint::kStroke_Style);
     71 
     72             SkPath path;
     73             for (size_t i = 0; i < count - 1; i++) {
     74                 path.moveTo(pts[i]);
     75                 path.lineTo(pts[i + 1]);
     76                 this->drawPath(path, strokedPaint);
     77                 path.rewind();
     78             }
     79             break;
     80         }
     81         default:
     82             LOG_ALWAYS_FATAL("Unknown point type");
     83     }
     84 }
     85 
     86 void SkiaCanvasProxy::onDrawOval(const SkRect& rect, const SkPaint& paint) {
     87     mCanvas->drawOval(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, paint);
     88 }
     89 
     90 void SkiaCanvasProxy::onDrawRect(const SkRect& rect, const SkPaint& paint) {
     91     mCanvas->drawRect(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, paint);
     92 }
     93 
     94 void SkiaCanvasProxy::onDrawRRect(const SkRRect& roundRect, const SkPaint& paint) {
     95     if (!roundRect.isComplex()) {
     96         const SkRect& rect = roundRect.rect();
     97         SkVector radii = roundRect.getSimpleRadii();
     98         mCanvas->drawRoundRect(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, radii.fX, radii.fY,
     99                                paint);
    100     } else {
    101         SkPath path;
    102         path.addRRect(roundRect);
    103         mCanvas->drawPath(path, paint);
    104     }
    105 }
    106 
    107 void SkiaCanvasProxy::onDrawArc(const SkRect& rect, SkScalar startAngle, SkScalar sweepAngle,
    108                                 bool useCenter, const SkPaint& paint) {
    109     mCanvas->drawArc(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, startAngle, sweepAngle,
    110                      useCenter, paint);
    111 }
    112 
    113 void SkiaCanvasProxy::onDrawPath(const SkPath& path, const SkPaint& paint) {
    114     mCanvas->drawPath(path, paint);
    115 }
    116 
    117 void SkiaCanvasProxy::onDrawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar top,
    118                                    const SkPaint* paint) {
    119     sk_sp<Bitmap> hwuiBitmap = Bitmap::createFrom(bitmap.info(), *bitmap.pixelRef());
    120     // HWUI doesn't support extractSubset(), so convert any subsetted bitmap into
    121     // a drawBitmapRect(); pass through an un-subsetted bitmap.
    122     if (hwuiBitmap && bitmap.dimensions() != hwuiBitmap->info().dimensions()) {
    123         SkIPoint origin = bitmap.pixelRefOrigin();
    124         mCanvas->drawBitmap(
    125                 *hwuiBitmap, origin.fX, origin.fY, origin.fX + bitmap.dimensions().width(),
    126                 origin.fY + bitmap.dimensions().height(), left, top,
    127                 left + bitmap.dimensions().width(), top + bitmap.dimensions().height(), paint);
    128     } else {
    129         mCanvas->drawBitmap(*hwuiBitmap, left, top, paint);
    130     }
    131 }
    132 
    133 void SkiaCanvasProxy::onDrawBitmapRect(const SkBitmap& skBitmap, const SkRect* srcPtr,
    134                                        const SkRect& dst, const SkPaint* paint, SrcRectConstraint) {
    135     SkRect src = (srcPtr) ? *srcPtr : SkRect::MakeWH(skBitmap.width(), skBitmap.height());
    136     // TODO: if bitmap is a subset, do we need to add pixelRefOrigin to src?
    137     Bitmap* bitmap = reinterpret_cast<Bitmap*>(skBitmap.pixelRef());
    138     mCanvas->drawBitmap(*bitmap, src.fLeft, src.fTop, src.fRight, src.fBottom, dst.fLeft, dst.fTop,
    139                         dst.fRight, dst.fBottom, paint);
    140 }
    141 
    142 void SkiaCanvasProxy::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
    143                                        const SkRect& dst, const SkPaint*) {
    144     // TODO make nine-patch drawing a method on Canvas.h
    145     SkDEBUGFAIL("SkiaCanvasProxy::onDrawBitmapNine is not yet supported");
    146 }
    147 
    148 void SkiaCanvasProxy::onDrawImage(const SkImage* image, SkScalar left, SkScalar top,
    149                                   const SkPaint* paint) {
    150     SkBitmap skiaBitmap;
    151     SkPixmap pixmap;
    152     if (image->peekPixels(&pixmap) && skiaBitmap.installPixels(pixmap)) {
    153         onDrawBitmap(skiaBitmap, left, top, paint);
    154     }
    155 }
    156 
    157 void SkiaCanvasProxy::onDrawImageRect(const SkImage* image, const SkRect* srcPtr, const SkRect& dst,
    158                                       const SkPaint* paint, SrcRectConstraint constraint) {
    159     SkBitmap skiaBitmap;
    160     SkPixmap pixmap;
    161     if (image->peekPixels(&pixmap) && skiaBitmap.installPixels(pixmap)) {
    162         sk_sp<Bitmap> bitmap = Bitmap::createFrom(skiaBitmap.info(), *skiaBitmap.pixelRef());
    163         SkRect src = (srcPtr) ? *srcPtr : SkRect::MakeWH(image->width(), image->height());
    164         mCanvas->drawBitmap(*bitmap, src.fLeft, src.fTop, src.fRight, src.fBottom, dst.fLeft,
    165                             dst.fTop, dst.fRight, dst.fBottom, paint);
    166     }
    167 }
    168 
    169 void SkiaCanvasProxy::onDrawImageNine(const SkImage*, const SkIRect& center, const SkRect& dst,
    170                                       const SkPaint*) {
    171     SkDEBUGFAIL("SkiaCanvasProxy::onDrawImageNine is not yet supported");
    172 }
    173 
    174 void SkiaCanvasProxy::onDrawImageLattice(const SkImage* image, const Lattice& lattice,
    175                                          const SkRect& dst, const SkPaint* paint) {
    176     SkLatticeIter iter(lattice, dst);
    177     SkRect srcR, dstR;
    178     while (iter.next(&srcR, &dstR)) {
    179         onDrawImageRect(image, &srcR, dstR, paint, SkCanvas::kFast_SrcRectConstraint);
    180     }
    181 }
    182 
    183 void SkiaCanvasProxy::onDrawVerticesObject(const SkVertices* vertices, SkBlendMode bmode,
    184                                            const SkPaint& paint) {
    185     if (mFilterHwuiCalls) {
    186         return;
    187     }
    188     mCanvas->drawVertices(vertices, bmode, paint);
    189 }
    190 
    191 sk_sp<SkSurface> SkiaCanvasProxy::onNewSurface(const SkImageInfo&, const SkSurfaceProps&) {
    192     SkDEBUGFAIL("SkiaCanvasProxy::onNewSurface is not supported");
    193     return NULL;
    194 }
    195 
    196 void SkiaCanvasProxy::willSave() {
    197     mCanvas->save(android::SaveFlags::MatrixClip);
    198 }
    199 
    200 static inline SaveFlags::Flags saveFlags(SkCanvas::SaveLayerFlags layerFlags) {
    201     SaveFlags::Flags saveFlags = 0;
    202 
    203     if (!(layerFlags & SkCanvas::kDontClipToLayer_Legacy_SaveLayerFlag)) {
    204         saveFlags |= SaveFlags::ClipToLayer;
    205     }
    206 
    207     return saveFlags;
    208 }
    209 
    210 SkCanvas::SaveLayerStrategy SkiaCanvasProxy::getSaveLayerStrategy(
    211         const SaveLayerRec& saveLayerRec) {
    212     SkRect rect;
    213     if (saveLayerRec.fBounds) {
    214         rect = *saveLayerRec.fBounds;
    215     } else if (!mCanvas->getClipBounds(&rect)) {
    216         rect = SkRect::MakeEmpty();
    217     }
    218     mCanvas->saveLayer(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, saveLayerRec.fPaint,
    219                        saveFlags(saveLayerRec.fSaveLayerFlags));
    220     return SkCanvas::kNoLayer_SaveLayerStrategy;
    221 }
    222 
    223 void SkiaCanvasProxy::willRestore() {
    224     mCanvas->restore();
    225 }
    226 
    227 void SkiaCanvasProxy::didConcat(const SkMatrix& matrix) {
    228     mCanvas->concat(matrix);
    229 }
    230 
    231 void SkiaCanvasProxy::didSetMatrix(const SkMatrix& matrix) {
    232     mCanvas->setMatrix(matrix);
    233 }
    234 
    235 void SkiaCanvasProxy::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
    236                                    const SkPaint& paint) {
    237     SkPath path;
    238     path.addRRect(outer);
    239     path.addRRect(inner);
    240     path.setFillType(SkPath::kEvenOdd_FillType);
    241     this->drawPath(path, paint);
    242 }
    243 
    244 /**
    245  * Utility class that converts the incoming text & paint from the given encoding
    246  * into glyphIDs.
    247  */
    248 class GlyphIDConverter {
    249 public:
    250     GlyphIDConverter(const void* text, size_t byteLength, const SkPaint& origPaint) {
    251         paint = origPaint;
    252         if (paint.getTextEncoding() == SkPaint::kGlyphID_TextEncoding) {
    253             glyphIDs = (uint16_t*)text;
    254             count = byteLength >> 1;
    255         } else {
    256             // ensure space for one glyph per ID given UTF8 encoding.
    257             storage.reset(new uint16_t[byteLength]);
    258             glyphIDs = storage.get();
    259             count = paint.textToGlyphs(text, byteLength, storage.get());
    260             paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
    261         }
    262     }
    263 
    264     SkPaint paint;
    265     uint16_t* glyphIDs;
    266     int count;
    267 
    268 private:
    269     std::unique_ptr<uint16_t[]> storage;
    270 };
    271 
    272 void SkiaCanvasProxy::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
    273                                  const SkPaint& origPaint) {
    274     // convert to glyphIDs if necessary
    275     GlyphIDConverter glyphs(text, byteLength, origPaint);
    276 
    277     // compute the glyph positions
    278     std::unique_ptr<SkScalar[]> glyphWidths(new SkScalar[glyphs.count]);
    279     glyphs.paint.getTextWidths(glyphs.glyphIDs, glyphs.count << 1, glyphWidths.get());
    280 
    281     // compute conservative bounds
    282     // NOTE: We could call the faster paint.getFontBounds for a less accurate,
    283     //       but even more conservative bounds if this  is too slow.
    284     SkRect bounds;
    285     glyphs.paint.measureText(glyphs.glyphIDs, glyphs.count << 1, &bounds);
    286 
    287     // adjust for non-left alignment
    288     if (glyphs.paint.getTextAlign() != SkPaint::kLeft_Align) {
    289         SkScalar stop = 0;
    290         for (int i = 0; i < glyphs.count; i++) {
    291             stop += glyphWidths[i];
    292         }
    293         if (glyphs.paint.getTextAlign() == SkPaint::kCenter_Align) {
    294             stop = SkScalarHalf(stop);
    295         }
    296         if (glyphs.paint.isVerticalText()) {
    297             y -= stop;
    298         } else {
    299             x -= stop;
    300         }
    301     }
    302 
    303     // setup the first glyph position and adjust bounds if needed
    304     int xBaseline = 0;
    305     int yBaseline = 0;
    306     if (mCanvas->drawTextAbsolutePos()) {
    307         bounds.offset(x, y);
    308         xBaseline = x;
    309         yBaseline = y;
    310     }
    311 
    312     static_assert(sizeof(SkPoint) == sizeof(float) * 2, "SkPoint is no longer two floats");
    313     auto glyphFunc = [&](uint16_t* text, float* positions) {
    314         memcpy(text, glyphs.glyphIDs, glyphs.count * sizeof(uint16_t));
    315         size_t posIndex = 0;
    316         // setup the first glyph position
    317         positions[posIndex++] = xBaseline;
    318         positions[posIndex++] = yBaseline;
    319         // setup the remaining glyph positions
    320         if (glyphs.paint.isVerticalText()) {
    321             float yPosition = yBaseline;
    322             for (int i = 1; i < glyphs.count; i++) {
    323                 positions[posIndex++] = xBaseline;
    324                 yPosition += glyphWidths[i - 1];
    325                 positions[posIndex++] = yPosition;
    326             }
    327         } else {
    328             float xPosition = xBaseline;
    329             for (int i = 1; i < glyphs.count; i++) {
    330                 xPosition += glyphWidths[i - 1];
    331                 positions[posIndex++] = xPosition;
    332                 positions[posIndex++] = yBaseline;
    333             }
    334         }
    335     };
    336     mCanvas->drawGlyphs(glyphFunc, glyphs.count, glyphs.paint, x, y, bounds.fLeft, bounds.fTop,
    337                         bounds.fRight, bounds.fBottom, 0);
    338 }
    339 
    340 void SkiaCanvasProxy::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
    341                                     const SkPaint& origPaint) {
    342     // convert to glyphIDs if necessary
    343     GlyphIDConverter glyphs(text, byteLength, origPaint);
    344 
    345     // convert to relative positions if necessary
    346     int x, y;
    347     if (mCanvas->drawTextAbsolutePos()) {
    348         x = 0;
    349         y = 0;
    350     } else {
    351         x = pos[0].fX;
    352         y = pos[0].fY;
    353     }
    354 
    355     // Compute conservative bounds.  If the content has already been processed
    356     // by Minikin then it had already computed these bounds.  Unfortunately,
    357     // there is no way to capture those bounds as part of the Skia drawPosText
    358     // API so we need to do that computation again here.
    359     SkRect bounds = SkRect::MakeEmpty();
    360     for (int i = 0; i < glyphs.count; i++) {
    361         SkRect glyphBounds = SkRect::MakeEmpty();
    362         glyphs.paint.measureText(&glyphs.glyphIDs[i], sizeof(uint16_t), &glyphBounds);
    363         glyphBounds.offset(pos[i].fX, pos[i].fY);
    364         bounds.join(glyphBounds);
    365     }
    366 
    367     static_assert(sizeof(SkPoint) == sizeof(float) * 2, "SkPoint is no longer two floats");
    368     auto glyphFunc = [&](uint16_t* text, float* positions) {
    369         memcpy(text, glyphs.glyphIDs, glyphs.count * sizeof(uint16_t));
    370         if (mCanvas->drawTextAbsolutePos()) {
    371             memcpy(positions, pos, 2 * glyphs.count * sizeof(float));
    372         } else {
    373             for (int i = 0, posIndex = 0; i < glyphs.count; i++) {
    374                 positions[posIndex++] = pos[i].fX - x;
    375                 positions[posIndex++] = pos[i].fY - y;
    376             }
    377         }
    378     };
    379     mCanvas->drawGlyphs(glyphFunc, glyphs.count, glyphs.paint, x, y, bounds.fLeft, bounds.fTop,
    380                         bounds.fRight, bounds.fBottom, 0);
    381 }
    382 
    383 void SkiaCanvasProxy::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
    384                                      SkScalar constY, const SkPaint& paint) {
    385     const size_t pointCount = byteLength >> 1;
    386     std::unique_ptr<SkPoint[]> pts(new SkPoint[pointCount]);
    387     for (size_t i = 0; i < pointCount; i++) {
    388         pts[i].set(xpos[i], constY);
    389     }
    390     this->onDrawPosText(text, byteLength, pts.get(), paint);
    391 }
    392 
    393 void SkiaCanvasProxy::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
    394                                        const SkMatrix* matrix, const SkPaint& origPaint) {
    395     SkDEBUGFAIL("SkiaCanvasProxy::onDrawTextOnPath is not supported");
    396 }
    397 
    398 void SkiaCanvasProxy::onDrawTextRSXform(const void* text, size_t byteLength,
    399                                         const SkRSXform xform[], const SkRect* cullRect,
    400                                         const SkPaint& paint) {
    401     GlyphIDConverter glyphs(text, byteLength, paint);  // Just get count
    402     SkMatrix localM, currM, origM;
    403     mCanvas->getMatrix(&currM);
    404     origM = currM;
    405     for (int i = 0; i < glyphs.count; i++) {
    406         localM.setRSXform(*xform++);
    407         currM.setConcat(origM, localM);
    408         mCanvas->setMatrix(currM);
    409         this->onDrawText((char*)text + (byteLength / glyphs.count * i), byteLength / glyphs.count,
    410                          0, 0, paint);
    411     }
    412     mCanvas->setMatrix(origM);
    413 }
    414 
    415 void SkiaCanvasProxy::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
    416                                      const SkPaint& paint) {
    417     SkPaint runPaint = paint;
    418 
    419     SkTextBlobRunIterator it(blob);
    420     for (; !it.done(); it.next()) {
    421         size_t textLen = it.glyphCount() * sizeof(uint16_t);
    422         const SkPoint& offset = it.offset();
    423         // applyFontToPaint() always overwrites the exact same attributes,
    424         // so it is safe to not re-seed the paint for this reason.
    425         it.applyFontToPaint(&runPaint);
    426 
    427         switch (it.positioning()) {
    428             case SkTextBlob::kDefault_Positioning:
    429                 this->drawText(it.glyphs(), textLen, x + offset.x(), y + offset.y(), runPaint);
    430                 break;
    431             case SkTextBlob::kHorizontal_Positioning: {
    432                 std::unique_ptr<SkPoint[]> pts(new SkPoint[it.glyphCount()]);
    433                 for (size_t i = 0; i < it.glyphCount(); i++) {
    434                     pts[i].set(x + offset.x() + it.pos()[i], y + offset.y());
    435                 }
    436                 this->drawPosText(it.glyphs(), textLen, pts.get(), runPaint);
    437                 break;
    438             }
    439             case SkTextBlob::kFull_Positioning: {
    440                 std::unique_ptr<SkPoint[]> pts(new SkPoint[it.glyphCount()]);
    441                 for (size_t i = 0; i < it.glyphCount(); i++) {
    442                     const size_t xIndex = i * 2;
    443                     const size_t yIndex = xIndex + 1;
    444                     pts[i].set(x + offset.x() + it.pos()[xIndex],
    445                                y + offset.y() + it.pos()[yIndex]);
    446                 }
    447                 this->drawPosText(it.glyphs(), textLen, pts.get(), runPaint);
    448                 break;
    449             }
    450             default:
    451                 SK_ABORT("unhandled positioning mode");
    452         }
    453     }
    454 }
    455 
    456 void SkiaCanvasProxy::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
    457                                   const SkPoint texCoords[4], SkBlendMode bmode,
    458                                   const SkPaint& paint) {
    459     if (mFilterHwuiCalls) {
    460         return;
    461     }
    462     SkMatrix matrix;
    463     mCanvas->getMatrix(&matrix);
    464     SkISize lod = SkPatchUtils::GetLevelOfDetail(cubics, &matrix);
    465 
    466     mCanvas->drawVertices(
    467             SkPatchUtils::MakeVertices(cubics, colors, texCoords, lod.width(), lod.height()).get(),
    468             bmode, paint);
    469 }
    470 
    471 void SkiaCanvasProxy::onClipRect(const SkRect& rect, SkClipOp op, ClipEdgeStyle) {
    472     mCanvas->clipRect(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, op);
    473 }
    474 
    475 void SkiaCanvasProxy::onClipRRect(const SkRRect& roundRect, SkClipOp op, ClipEdgeStyle) {
    476     SkPath path;
    477     path.addRRect(roundRect);
    478     mCanvas->clipPath(&path, op);
    479 }
    480 
    481 void SkiaCanvasProxy::onClipPath(const SkPath& path, SkClipOp op, ClipEdgeStyle) {
    482     mCanvas->clipPath(&path, op);
    483 }
    484 
    485 };  // namespace uirenderer
    486 };  // namespace android
    487