SkiaCanvasProxy.cpp revision 17c5adfa63872fbb6a903a5941e3c6455995b92d
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 <cutils/log.h> 20#include <SkPatchUtils.h> 21#include <SkPixelRef.h> 22 23namespace android { 24namespace uirenderer { 25 26SkiaCanvasProxy::SkiaCanvasProxy(Canvas* canvas, bool filterHwuiCalls) 27 : INHERITED(canvas->width(), canvas->height()) 28 , mCanvas(canvas) 29 , mFilterHwuiCalls(filterHwuiCalls) {} 30 31void SkiaCanvasProxy::onDrawPaint(const SkPaint& paint) { 32 mCanvas->drawPaint(paint); 33} 34 35void SkiaCanvasProxy::onDrawPoints(PointMode pointMode, size_t count, const SkPoint pts[], 36 const SkPaint& paint) { 37 if (!pts || count == 0) { 38 return; 39 } 40 41 // convert the SkPoints into floats 42 SK_COMPILE_ASSERT(sizeof(SkPoint) == sizeof(float)*2, SkPoint_is_no_longer_2_floats); 43 const size_t floatCount = count << 1; 44 const float* floatArray = &pts[0].fX; 45 46 switch (pointMode) { 47 case kPoints_PointMode: { 48 mCanvas->drawPoints(floatArray, floatCount, paint); 49 break; 50 } 51 case kLines_PointMode: { 52 mCanvas->drawLines(floatArray, floatCount, paint); 53 break; 54 } 55 case kPolygon_PointMode: { 56 SkPaint strokedPaint(paint); 57 strokedPaint.setStyle(SkPaint::kStroke_Style); 58 59 SkPath path; 60 for (size_t i = 0; i < count - 1; i++) { 61 path.moveTo(pts[i]); 62 path.lineTo(pts[i+1]); 63 this->drawPath(path, strokedPaint); 64 path.rewind(); 65 } 66 break; 67 } 68 default: 69 LOG_ALWAYS_FATAL("Unknown point type"); 70 } 71} 72 73void SkiaCanvasProxy::onDrawOval(const SkRect& rect, const SkPaint& paint) { 74 mCanvas->drawOval(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, paint); 75} 76 77void SkiaCanvasProxy::onDrawRect(const SkRect& rect, const SkPaint& paint) { 78 mCanvas->drawRect(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, paint); 79} 80 81void SkiaCanvasProxy::onDrawRRect(const SkRRect& roundRect, const SkPaint& paint) { 82 if (!roundRect.isComplex()) { 83 const SkRect& rect = roundRect.rect(); 84 SkVector radii = roundRect.getSimpleRadii(); 85 mCanvas->drawRoundRect(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, 86 radii.fX, radii.fY, paint); 87 } else { 88 SkPath path; 89 path.addRRect(roundRect); 90 mCanvas->drawPath(path, paint); 91 } 92} 93 94void SkiaCanvasProxy::onDrawPath(const SkPath& path, const SkPaint& paint) { 95 mCanvas->drawPath(path, paint); 96} 97 98void SkiaCanvasProxy::onDrawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar top, 99 const SkPaint* paint) { 100 SkPixelRef* pxRef = bitmap.pixelRef(); 101 102 // HWUI doesn't support extractSubset(), so convert any subsetted bitmap into 103 // a drawBitmapRect(); pass through an un-subsetted bitmap. 104 if (pxRef && bitmap.dimensions() != pxRef->info().dimensions()) { 105 SkBitmap fullBitmap; 106 fullBitmap.setInfo(pxRef->info()); 107 fullBitmap.setPixelRef(pxRef, 0, 0); 108 SkIPoint origin = bitmap.pixelRefOrigin(); 109 mCanvas->drawBitmap(fullBitmap, origin.fX, origin.fY, 110 origin.fX + bitmap.dimensions().width(), 111 origin.fY + bitmap.dimensions().height(), 112 left, top, 113 left + bitmap.dimensions().width(), 114 top + bitmap.dimensions().height(), 115 paint); 116 } else { 117 mCanvas->drawBitmap(bitmap, left, top, paint); 118 } 119} 120 121void SkiaCanvasProxy::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* srcPtr, 122 const SkRect& dst, const SkPaint* paint, DrawBitmapRectFlags) { 123 SkRect src = (srcPtr) ? *srcPtr : SkRect::MakeWH(bitmap.width(), bitmap.height()); 124 // TODO: if bitmap is a subset, do we need to add pixelRefOrigin to src? 125 mCanvas->drawBitmap(bitmap, src.fLeft, src.fTop, src.fRight, src.fBottom, 126 dst.fLeft, dst.fTop, dst.fRight, dst.fBottom, paint); 127} 128 129void SkiaCanvasProxy::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, 130 const SkRect& dst, const SkPaint*) { 131 //TODO make nine-patch drawing a method on Canvas.h 132 SkDEBUGFAIL("SkiaCanvasProxy::onDrawBitmapNine is not yet supported"); 133} 134 135void SkiaCanvasProxy::onDrawSprite(const SkBitmap& bitmap, int left, int top, 136 const SkPaint* paint) { 137 // TODO: if bitmap is a subset, do we need to add pixelRefOrigin to src? 138 mCanvas->save(SkCanvas::kMatrixClip_SaveFlag); 139 mCanvas->setMatrix(SkMatrix::I()); 140 mCanvas->drawBitmap(bitmap, left, top, paint); 141 mCanvas->restore(); 142} 143 144void SkiaCanvasProxy::onDrawVertices(VertexMode mode, int vertexCount, const SkPoint vertices[], 145 const SkPoint texs[], const SkColor colors[], SkXfermode*, const uint16_t indices[], 146 int indexCount, const SkPaint& paint) { 147 if (mFilterHwuiCalls) { 148 return; 149 } 150 // convert the SkPoints into floats 151 SK_COMPILE_ASSERT(sizeof(SkPoint) == sizeof(float)*2, SkPoint_is_no_longer_2_floats); 152 const int floatCount = vertexCount << 1; 153 const float* vArray = &vertices[0].fX; 154 const float* tArray = (texs) ? &texs[0].fX : NULL; 155 const int* cArray = (colors) ? (int*)colors : NULL; 156 mCanvas->drawVertices(mode, floatCount, vArray, tArray, cArray, indices, indexCount, paint); 157} 158 159SkSurface* SkiaCanvasProxy::onNewSurface(const SkImageInfo&, const SkSurfaceProps&) { 160 SkDEBUGFAIL("SkiaCanvasProxy::onNewSurface is not supported"); 161 return NULL; 162} 163 164void SkiaCanvasProxy::willSave() { 165 mCanvas->save(SkCanvas::kMatrixClip_SaveFlag); 166} 167 168SkCanvas::SaveLayerStrategy SkiaCanvasProxy::willSaveLayer(const SkRect* rectPtr, 169 const SkPaint* paint, SaveFlags flags) { 170 SkRect rect; 171 if (rectPtr) { 172 rect = *rectPtr; 173 } else if(!mCanvas->getClipBounds(&rect)) { 174 rect = SkRect::MakeEmpty(); 175 } 176 mCanvas->saveLayer(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, paint, flags); 177 return SkCanvas::kNoLayer_SaveLayerStrategy; 178} 179 180void SkiaCanvasProxy::willRestore() { 181 mCanvas->restore(); 182} 183 184void SkiaCanvasProxy::didConcat(const SkMatrix& matrix) { 185 mCanvas->concat(matrix); 186} 187 188void SkiaCanvasProxy::didSetMatrix(const SkMatrix& matrix) { 189 mCanvas->setMatrix(matrix); 190} 191 192void SkiaCanvasProxy::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, 193 const SkPaint& paint) { 194 SkPath path; 195 path.addRRect(outer); 196 path.addRRect(inner); 197 path.setFillType(SkPath::kEvenOdd_FillType); 198 this->drawPath(path, paint); 199} 200 201/** 202 * Utility class that converts the incoming text & paint from the given encoding 203 * into glyphIDs. 204 */ 205class GlyphIDConverter { 206public: 207 GlyphIDConverter(const void* text, size_t byteLength, const SkPaint& origPaint) { 208 paint = origPaint; 209 if (paint.getTextEncoding() == SkPaint::kGlyphID_TextEncoding) { 210 glyphIDs = (uint16_t*)text; 211 count = byteLength >> 1; 212 } else { 213 storage.reset(byteLength); // ensures space for one glyph per ID given UTF8 encoding. 214 glyphIDs = storage.get(); 215 count = paint.textToGlyphs(text, byteLength, storage.get()); 216 paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); 217 } 218 } 219 220 SkPaint paint; 221 uint16_t* glyphIDs; 222 int count; 223private: 224 SkAutoSTMalloc<32, uint16_t> storage; 225}; 226 227void SkiaCanvasProxy::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y, 228 const SkPaint& origPaint) { 229 // convert to glyphIDs if necessary 230 GlyphIDConverter glyphs(text, byteLength, origPaint); 231 232 // compute the glyph positions 233 SkAutoSTMalloc<32, SkPoint> pointStorage(glyphs.count); 234 SkAutoSTMalloc<32, SkScalar> glyphWidths(glyphs.count); 235 glyphs.paint.getTextWidths(glyphs.glyphIDs, glyphs.count << 1, glyphWidths.get()); 236 237 // compute conservative bounds 238 // NOTE: We could call the faster paint.getFontBounds for a less accurate, 239 // but even more conservative bounds if this is too slow. 240 SkRect bounds; 241 glyphs.paint.measureText(glyphs.glyphIDs, glyphs.count << 1, &bounds); 242 243 // adjust for non-left alignment 244 if (glyphs.paint.getTextAlign() != SkPaint::kLeft_Align) { 245 SkScalar stop = 0; 246 for (int i = 0; i < glyphs.count; i++) { 247 stop += glyphWidths[i]; 248 } 249 if (glyphs.paint.getTextAlign() == SkPaint::kCenter_Align) { 250 stop = SkScalarHalf(stop); 251 } 252 if (glyphs.paint.isVerticalText()) { 253 y -= stop; 254 } else { 255 x -= stop; 256 } 257 } 258 259 // setup the first glyph position and adjust bounds if needed 260 int xBaseline = 0; 261 int yBaseline = 0; 262 if (mCanvas->drawTextAbsolutePos()) { 263 bounds.offset(x,y); 264 xBaseline = x; 265 yBaseline = y; 266 } 267 pointStorage[0].set(xBaseline, yBaseline); 268 269 // setup the remaining glyph positions 270 if (glyphs.paint.isVerticalText()) { 271 for (int i = 1; i < glyphs.count; i++) { 272 pointStorage[i].set(xBaseline, glyphWidths[i-1] + pointStorage[i-1].fY); 273 } 274 } else { 275 for (int i = 1; i < glyphs.count; i++) { 276 pointStorage[i].set(glyphWidths[i-1] + pointStorage[i-1].fX, yBaseline); 277 } 278 } 279 280 SK_COMPILE_ASSERT(sizeof(SkPoint) == sizeof(float)*2, SkPoint_is_no_longer_2_floats); 281 mCanvas->drawText(glyphs.glyphIDs, &pointStorage[0].fX, glyphs.count, glyphs.paint, 282 x, y, bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom, 0); 283} 284 285void SkiaCanvasProxy::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[], 286 const SkPaint& origPaint) { 287 // convert to glyphIDs if necessary 288 GlyphIDConverter glyphs(text, byteLength, origPaint); 289 290 // convert to relative positions if necessary 291 int x, y; 292 const SkPoint* posArray; 293 SkAutoSTMalloc<32, SkPoint> pointStorage; 294 if (mCanvas->drawTextAbsolutePos()) { 295 x = 0; 296 y = 0; 297 posArray = pos; 298 } else { 299 x = pos[0].fX; 300 y = pos[0].fY; 301 posArray = pointStorage.reset(glyphs.count); 302 for (int i = 0; i < glyphs.count; i++) { 303 pointStorage[i].fX = pos[i].fX- x; 304 pointStorage[i].fY = pos[i].fY- y; 305 } 306 } 307 308 // compute conservative bounds 309 // NOTE: We could call the faster paint.getFontBounds for a less accurate, 310 // but even more conservative bounds if this is too slow. 311 SkRect bounds; 312 glyphs.paint.measureText(glyphs.glyphIDs, glyphs.count << 1, &bounds); 313 bounds.offset(x, y); 314 315 SK_COMPILE_ASSERT(sizeof(SkPoint) == sizeof(float)*2, SkPoint_is_no_longer_2_floats); 316 mCanvas->drawText(glyphs.glyphIDs, &posArray[0].fX, glyphs.count, glyphs.paint, x, y, 317 bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom, 0); 318} 319 320void SkiaCanvasProxy::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[], 321 SkScalar constY, const SkPaint& paint) { 322 const size_t pointCount = byteLength >> 1; 323 SkAutoSTMalloc<32, SkPoint> storage(pointCount); 324 SkPoint* pts = storage.get(); 325 for (size_t i = 0; i < pointCount; i++) { 326 pts[i].set(xpos[i], constY); 327 } 328 this->onDrawPosText(text, byteLength, pts, paint); 329} 330 331void SkiaCanvasProxy::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path, 332 const SkMatrix* matrix, const SkPaint& origPaint) { 333 // convert to glyphIDs if necessary 334 GlyphIDConverter glyphs(text, byteLength, origPaint); 335 mCanvas->drawTextOnPath(glyphs.glyphIDs, glyphs.count, path, 0, 0, glyphs.paint); 336} 337 338void SkiaCanvasProxy::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y, 339 const SkPaint& paint) { 340 SkDEBUGFAIL("SkiaCanvasProxy::onDrawTextBlob is not supported"); 341} 342 343void SkiaCanvasProxy::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4], 344 const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) { 345 if (mFilterHwuiCalls) { 346 return; 347 } 348 SkPatchUtils::VertexData data; 349 350 SkMatrix matrix; 351 mCanvas->getMatrix(&matrix); 352 SkISize lod = SkPatchUtils::GetLevelOfDetail(cubics, &matrix); 353 354 // It automatically adjusts lodX and lodY in case it exceeds the number of indices. 355 // If it fails to generate the vertices, then we do not draw. 356 if (SkPatchUtils::getVertexData(&data, cubics, colors, texCoords, lod.width(), lod.height())) { 357 this->drawVertices(SkCanvas::kTriangles_VertexMode, data.fVertexCount, data.fPoints, 358 data.fTexCoords, data.fColors, xmode, data.fIndices, data.fIndexCount, 359 paint); 360 } 361} 362 363void SkiaCanvasProxy::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle) { 364 mCanvas->clipRect(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, op); 365} 366 367void SkiaCanvasProxy::onClipRRect(const SkRRect& roundRect, SkRegion::Op op, ClipEdgeStyle) { 368 SkPath path; 369 path.addRRect(roundRect); 370 mCanvas->clipPath(&path, op); 371} 372 373void SkiaCanvasProxy::onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle) { 374 mCanvas->clipPath(&path, op); 375} 376 377void SkiaCanvasProxy::onClipRegion(const SkRegion& region, SkRegion::Op op) { 378 mCanvas->clipRegion(®ion, op); 379} 380 381}; // namespace uirenderer 382}; // namespace android 383