SkiaCanvas.cpp revision 8872b38ef403cc2c44aca07d392f5e9426fd7f54
1/* 2 * Copyright (C) 2014 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 "jni.h" 18#include "Canvas.h" 19#include "GraphicsJNI.h" 20#include <android_runtime/AndroidRuntime.h> 21 22#include "SkCanvas.h" 23#include "SkClipStack.h" 24#include "SkDevice.h" 25#include "SkDeque.h" 26#include "SkDrawFilter.h" 27#include "SkGraphics.h" 28#include "SkPorterDuff.h" 29#include "SkShader.h" 30#include "SkTArray.h" 31#include "SkTemplates.h" 32 33#include <minikin/Layout.h> 34#include "MinikinSkia.h" 35#include "MinikinUtils.h" 36 37#include "TypefaceImpl.h" 38 39#include "unicode/ubidi.h" 40#include "unicode/ushape.h" 41 42#include <utils/Log.h> 43 44namespace android { 45 46// Holds an SkCanvas reference plus additional native data. 47class SkiaCanvas : public Canvas { 48public: 49 SkiaCanvas(SkBitmap* bitmap); 50 51 SkiaCanvas(SkCanvas* canvas) : mCanvas(canvas) { 52 SkASSERT(canvas); 53 } 54 55 virtual SkCanvas* getSkCanvas() { 56 return mCanvas.get(); 57 } 58 59 virtual void setBitmap(SkBitmap* bitmap, bool copyState); 60 61 virtual bool isOpaque(); 62 virtual int width(); 63 virtual int height(); 64 65 virtual int getSaveCount() const; 66 virtual int save(SkCanvas::SaveFlags flags); 67 virtual void restore(); 68 virtual void restoreToCount(int saveCount); 69 70 virtual int saveLayer(float left, float top, float right, float bottom, 71 const SkPaint* paint, SkCanvas::SaveFlags flags); 72 virtual int saveLayerAlpha(float left, float top, float right, float bottom, 73 int alpha, SkCanvas::SaveFlags flags); 74 75 virtual void getMatrix(SkMatrix* outMatrix) const; 76 virtual void setMatrix(const SkMatrix& matrix); 77 virtual void concat(const SkMatrix& matrix); 78 virtual void rotate(float degrees); 79 virtual void scale(float sx, float sy); 80 virtual void skew(float sx, float sy); 81 virtual void translate(float dx, float dy); 82 83 virtual bool getClipBounds(SkRect* outRect) const; 84 virtual bool quickRejectRect(float left, float top, float right, float bottom) const; 85 virtual bool quickRejectPath(const SkPath& path) const; 86 virtual bool clipRect(float left, float top, float right, float bottom, SkRegion::Op op); 87 virtual bool clipPath(const SkPath* path, SkRegion::Op op); 88 virtual bool clipRegion(const SkRegion* region, SkRegion::Op op); 89 90 virtual void setDrawFilter(SkDrawFilter* drawFilter); 91 92 virtual void drawColor(int color, SkXfermode::Mode mode); 93 virtual void drawPaint(const SkPaint& paint); 94 95 virtual void drawPoint(float x, float y, const SkPaint& paint); 96 virtual void drawPoints(const float* points, int count, const SkPaint& paint); 97 virtual void drawLine(float startX, float startY, float stopX, float stopY, 98 const SkPaint& paint); 99 virtual void drawLines(const float* points, int count, const SkPaint& paint); 100 virtual void drawRect(float left, float top, float right, float bottom, const SkPaint& paint); 101 virtual void drawRoundRect(float left, float top, float right, float bottom, 102 float rx, float ry, const SkPaint& paint); 103 virtual void drawCircle(float x, float y, float radius, const SkPaint& paint); 104 virtual void drawOval(float left, float top, float right, float bottom, const SkPaint& paint); 105 virtual void drawArc(float left, float top, float right, float bottom, 106 float startAngle, float sweepAngle, bool useCenter, const SkPaint& paint); 107 virtual void drawPath(const SkPath& path, const SkPaint& paint); 108 virtual void drawVertices(SkCanvas::VertexMode vertexMode, int vertexCount, 109 const float* verts, const float* tex, const int* colors, 110 const uint16_t* indices, int indexCount, const SkPaint& paint); 111 112 virtual void drawBitmap(const SkBitmap& bitmap, float left, float top, const SkPaint* paint); 113 virtual void drawBitmap(const SkBitmap& bitmap, const SkMatrix& matrix, const SkPaint* paint); 114 virtual void drawBitmap(const SkBitmap& bitmap, float srcLeft, float srcTop, 115 float srcRight, float srcBottom, float dstLeft, float dstTop, 116 float dstRight, float dstBottom, const SkPaint* paint); 117 virtual void drawBitmapMesh(const SkBitmap& bitmap, int meshWidth, int meshHeight, 118 const float* vertices, const int* colors, const SkPaint* paint); 119 120 virtual void drawText(const uint16_t* text, int start, int count, int contextCount, 121 float x, float y, int bidiFlags, const SkPaint& paint, TypefaceImpl* typeface); 122 virtual void drawPosText(const uint16_t* text, const float* positions, int count, 123 int posCount, const SkPaint& paint); 124 virtual void drawTextOnPath(const uint16_t* glyphs, int count, const SkPath& path, 125 float hOffset, float vOffset, const SkPaint& paint); 126 127private: 128 struct SaveRec { 129 int saveCount; 130 SkCanvas::SaveFlags saveFlags; 131 }; 132 133 void recordPartialSave(SkCanvas::SaveFlags flags); 134 void saveClipsForFrame(SkTArray<SkClipStack::Element>& clips, int frameSaveCount); 135 void applyClips(const SkTArray<SkClipStack::Element>& clips); 136 137 void drawPoints(const float* points, int count, const SkPaint& paint, 138 SkCanvas::PointMode mode); 139 void drawTextDecorations(float x, float y, float length, const SkPaint& paint); 140 141 SkAutoTUnref<SkCanvas> mCanvas; 142 SkAutoTDelete<SkDeque> mSaveStack; // lazily allocated, tracks partial saves. 143}; 144 145// Construct an SkCanvas from the bitmap. 146static SkCanvas* createCanvas(SkBitmap* bitmap) { 147 if (bitmap) { 148 return SkNEW_ARGS(SkCanvas, (*bitmap)); 149 } 150 151 // Create an empty bitmap device to prevent callers from crashing 152 // if they attempt to draw into this canvas. 153 SkBitmap emptyBitmap; 154 return new SkCanvas(emptyBitmap); 155} 156 157Canvas* Canvas::create_canvas(SkBitmap* bitmap) { 158 return new SkiaCanvas(bitmap); 159} 160 161Canvas* Canvas::create_canvas(SkCanvas* skiaCanvas) { 162 return new SkiaCanvas(skiaCanvas); 163} 164 165SkiaCanvas::SkiaCanvas(SkBitmap* bitmap) { 166 mCanvas.reset(createCanvas(bitmap)); 167} 168 169// ---------------------------------------------------------------------------- 170// Canvas state operations: Replace Bitmap 171// ---------------------------------------------------------------------------- 172 173class ClipCopier : public SkCanvas::ClipVisitor { 174public: 175 ClipCopier(SkCanvas* dstCanvas) : m_dstCanvas(dstCanvas) {} 176 177 virtual void clipRect(const SkRect& rect, SkRegion::Op op, bool antialias) { 178 m_dstCanvas->clipRect(rect, op, antialias); 179 } 180 virtual void clipRRect(const SkRRect& rrect, SkRegion::Op op, bool antialias) { 181 m_dstCanvas->clipRRect(rrect, op, antialias); 182 } 183 virtual void clipPath(const SkPath& path, SkRegion::Op op, bool antialias) { 184 m_dstCanvas->clipPath(path, op, antialias); 185 } 186 187private: 188 SkCanvas* m_dstCanvas; 189}; 190 191void SkiaCanvas::setBitmap(SkBitmap* bitmap, bool copyState) { 192 SkCanvas* newCanvas = createCanvas(bitmap); 193 SkASSERT(newCanvas); 194 195 if (copyState) { 196 // Copy the canvas matrix & clip state. 197 newCanvas->setMatrix(mCanvas->getTotalMatrix()); 198 if (NULL != mCanvas->getDevice() && NULL != newCanvas->getDevice()) { 199 ClipCopier copier(newCanvas); 200 mCanvas->replayClips(&copier); 201 } 202 } 203 204 // unrefs the existing canvas 205 mCanvas.reset(newCanvas); 206 207 // clean up the old save stack 208 mSaveStack.reset(NULL); 209} 210 211// ---------------------------------------------------------------------------- 212// Canvas state operations 213// ---------------------------------------------------------------------------- 214 215bool SkiaCanvas::isOpaque() { 216 return mCanvas->getDevice()->accessBitmap(false).isOpaque(); 217} 218 219int SkiaCanvas::width() { 220 return mCanvas->getBaseLayerSize().width(); 221} 222 223int SkiaCanvas::height() { 224 return mCanvas->getBaseLayerSize().height(); 225} 226 227// ---------------------------------------------------------------------------- 228// Canvas state operations: Save (layer) 229// ---------------------------------------------------------------------------- 230 231int SkiaCanvas::getSaveCount() const { 232 return mCanvas->getSaveCount(); 233} 234 235int SkiaCanvas::save(SkCanvas::SaveFlags flags) { 236 int count = mCanvas->save(); 237 recordPartialSave(flags); 238 return count; 239} 240 241void SkiaCanvas::restore() { 242 const SaveRec* rec = (NULL == mSaveStack.get()) 243 ? NULL 244 : static_cast<SaveRec*>(mSaveStack->back()); 245 int currentSaveCount = mCanvas->getSaveCount() - 1; 246 SkASSERT(NULL == rec || currentSaveCount >= rec->saveCount); 247 248 if (NULL == rec || rec->saveCount != currentSaveCount) { 249 // Fast path - no record for this frame. 250 mCanvas->restore(); 251 return; 252 } 253 254 bool preserveMatrix = !(rec->saveFlags & SkCanvas::kMatrix_SaveFlag); 255 bool preserveClip = !(rec->saveFlags & SkCanvas::kClip_SaveFlag); 256 257 SkMatrix savedMatrix; 258 if (preserveMatrix) { 259 savedMatrix = mCanvas->getTotalMatrix(); 260 } 261 262 SkTArray<SkClipStack::Element> savedClips; 263 if (preserveClip) { 264 saveClipsForFrame(savedClips, currentSaveCount); 265 } 266 267 mCanvas->restore(); 268 269 if (preserveMatrix) { 270 mCanvas->setMatrix(savedMatrix); 271 } 272 273 if (preserveClip && !savedClips.empty()) { 274 applyClips(savedClips); 275 } 276 277 mSaveStack->pop_back(); 278} 279 280void SkiaCanvas::restoreToCount(int restoreCount) { 281 while (mCanvas->getSaveCount() > restoreCount) { 282 this->restore(); 283 } 284} 285 286int SkiaCanvas::saveLayer(float left, float top, float right, float bottom, 287 const SkPaint* paint, SkCanvas::SaveFlags flags) { 288 SkRect bounds = SkRect::MakeLTRB(left, top, right, bottom); 289 int count = mCanvas->saveLayer(&bounds, paint, flags | SkCanvas::kMatrixClip_SaveFlag); 290 recordPartialSave(flags); 291 return count; 292} 293 294int SkiaCanvas::saveLayerAlpha(float left, float top, float right, float bottom, 295 int alpha, SkCanvas::SaveFlags flags) { 296 SkRect bounds = SkRect::MakeLTRB(left, top, right, bottom); 297 int count = mCanvas->saveLayerAlpha(&bounds, alpha, flags | SkCanvas::kMatrixClip_SaveFlag); 298 recordPartialSave(flags); 299 return count; 300} 301 302// ---------------------------------------------------------------------------- 303// functions to emulate legacy SaveFlags (i.e. independent matrix/clip flags) 304// ---------------------------------------------------------------------------- 305 306void SkiaCanvas::recordPartialSave(SkCanvas::SaveFlags flags) { 307 // A partial save is a save operation which doesn't capture the full canvas state. 308 // (either kMatrix_SaveFlags or kClip_SaveFlag is missing). 309 310 // Mask-out non canvas state bits. 311 flags = static_cast<SkCanvas::SaveFlags>(flags & SkCanvas::kMatrixClip_SaveFlag); 312 313 if (SkCanvas::kMatrixClip_SaveFlag == flags) { 314 // not a partial save. 315 return; 316 } 317 318 if (NULL == mSaveStack.get()) { 319 mSaveStack.reset(SkNEW_ARGS(SkDeque, (sizeof(struct SaveRec), 8))); 320 } 321 322 SaveRec* rec = static_cast<SaveRec*>(mSaveStack->push_back()); 323 // Store the save counter in the SkClipStack domain. 324 // (0-based, equal to the number of save ops on the stack). 325 rec->saveCount = mCanvas->getSaveCount() - 1; 326 rec->saveFlags = flags; 327} 328 329void SkiaCanvas::saveClipsForFrame(SkTArray<SkClipStack::Element>& clips, int frameSaveCount) { 330 SkClipStack::Iter clipIterator(*mCanvas->getClipStack(), 331 SkClipStack::Iter::kTop_IterStart); 332 while (const SkClipStack::Element* elem = clipIterator.next()) { 333 if (elem->getSaveCount() < frameSaveCount) { 334 // done with the current frame. 335 break; 336 } 337 SkASSERT(elem->getSaveCount() == frameSaveCount); 338 clips.push_back(*elem); 339 } 340} 341 342void SkiaCanvas::applyClips(const SkTArray<SkClipStack::Element>& clips) { 343 ClipCopier clipCopier(mCanvas); 344 345 // The clip stack stores clips in device space. 346 SkMatrix origMatrix = mCanvas->getTotalMatrix(); 347 mCanvas->resetMatrix(); 348 349 // We pushed the clips in reverse order. 350 for (int i = clips.count() - 1; i >= 0; --i) { 351 clips[i].replay(&clipCopier); 352 } 353 354 mCanvas->setMatrix(origMatrix); 355} 356 357// ---------------------------------------------------------------------------- 358// Canvas state operations: Matrix 359// ---------------------------------------------------------------------------- 360 361void SkiaCanvas::getMatrix(SkMatrix* outMatrix) const { 362 *outMatrix = mCanvas->getTotalMatrix(); 363} 364 365void SkiaCanvas::setMatrix(const SkMatrix& matrix) { 366 mCanvas->setMatrix(matrix); 367} 368 369void SkiaCanvas::concat(const SkMatrix& matrix) { 370 mCanvas->concat(matrix); 371} 372 373void SkiaCanvas::rotate(float degrees) { 374 mCanvas->rotate(degrees); 375} 376 377void SkiaCanvas::scale(float sx, float sy) { 378 mCanvas->scale(sx, sy); 379} 380 381void SkiaCanvas::skew(float sx, float sy) { 382 mCanvas->skew(sx, sy); 383} 384 385void SkiaCanvas::translate(float dx, float dy) { 386 mCanvas->translate(dx, dy); 387} 388 389// ---------------------------------------------------------------------------- 390// Canvas state operations: Clips 391// ---------------------------------------------------------------------------- 392 393// This function is a mirror of SkCanvas::getClipBounds except that it does 394// not outset the edge of the clip to account for anti-aliasing. There is 395// a skia bug to investigate pushing this logic into back into skia. 396// (see https://code.google.com/p/skia/issues/detail?id=1303) 397bool SkiaCanvas::getClipBounds(SkRect* outRect) const { 398 SkIRect ibounds; 399 if (!mCanvas->getClipDeviceBounds(&ibounds)) { 400 return false; 401 } 402 403 SkMatrix inverse; 404 // if we can't invert the CTM, we can't return local clip bounds 405 if (!mCanvas->getTotalMatrix().invert(&inverse)) { 406 if (outRect) { 407 outRect->setEmpty(); 408 } 409 return false; 410 } 411 412 if (NULL != outRect) { 413 SkRect r = SkRect::Make(ibounds); 414 inverse.mapRect(outRect, r); 415 } 416 return true; 417} 418 419bool SkiaCanvas::quickRejectRect(float left, float top, float right, float bottom) const { 420 SkRect bounds = SkRect::MakeLTRB(left, top, right, bottom); 421 return mCanvas->quickReject(bounds); 422} 423 424bool SkiaCanvas::quickRejectPath(const SkPath& path) const { 425 return mCanvas->quickReject(path); 426} 427 428bool SkiaCanvas::clipRect(float left, float top, float right, float bottom, SkRegion::Op op) { 429 SkRect rect = SkRect::MakeLTRB(left, top, right, bottom); 430 mCanvas->clipRect(rect, op); 431 return mCanvas->isClipEmpty(); 432} 433 434bool SkiaCanvas::clipPath(const SkPath* path, SkRegion::Op op) { 435 mCanvas->clipPath(*path, op); 436 return mCanvas->isClipEmpty(); 437} 438 439bool SkiaCanvas::clipRegion(const SkRegion* region, SkRegion::Op op) { 440 SkPath rgnPath; 441 if (region->getBoundaryPath(&rgnPath)) { 442 // The region is specified in device space. 443 SkMatrix savedMatrix = mCanvas->getTotalMatrix(); 444 mCanvas->resetMatrix(); 445 mCanvas->clipPath(rgnPath, op); 446 mCanvas->setMatrix(savedMatrix); 447 } else { 448 mCanvas->clipRect(SkRect::MakeEmpty(), op); 449 } 450 return mCanvas->isClipEmpty(); 451} 452 453// ---------------------------------------------------------------------------- 454// Canvas state operations: Filters 455// ---------------------------------------------------------------------------- 456 457void SkiaCanvas::setDrawFilter(SkDrawFilter* drawFilter) { 458 mCanvas->setDrawFilter(drawFilter); 459} 460 461// ---------------------------------------------------------------------------- 462// Canvas draw operations 463// ---------------------------------------------------------------------------- 464 465void SkiaCanvas::drawColor(int color, SkXfermode::Mode mode) { 466 mCanvas->drawColor(color, mode); 467} 468 469void SkiaCanvas::drawPaint(const SkPaint& paint) { 470 mCanvas->drawPaint(paint); 471} 472 473// ---------------------------------------------------------------------------- 474// Canvas draw operations: Geometry 475// ---------------------------------------------------------------------------- 476 477void SkiaCanvas::drawPoints(const float* points, int count, const SkPaint& paint, 478 SkCanvas::PointMode mode) { 479 // convert the floats into SkPoints 480 count >>= 1; // now it is the number of points 481 SkAutoSTMalloc<32, SkPoint> storage(count); 482 SkPoint* pts = storage.get(); 483 for (int i = 0; i < count; i++) { 484 pts[i].set(points[0], points[1]); 485 points += 2; 486 } 487 mCanvas->drawPoints(mode, count, pts, paint); 488} 489 490 491void SkiaCanvas::drawPoint(float x, float y, const SkPaint& paint) { 492 mCanvas->drawPoint(x, y, paint); 493} 494 495void SkiaCanvas::drawPoints(const float* points, int count, const SkPaint& paint) { 496 this->drawPoints(points, count, paint, SkCanvas::kPoints_PointMode); 497} 498 499void SkiaCanvas::drawLine(float startX, float startY, float stopX, float stopY, 500 const SkPaint& paint) { 501 mCanvas->drawLine(startX, startY, stopX, stopY, paint); 502} 503 504void SkiaCanvas::drawLines(const float* points, int count, const SkPaint& paint) { 505 this->drawPoints(points, count, paint, SkCanvas::kLines_PointMode); 506} 507 508void SkiaCanvas::drawRect(float left, float top, float right, float bottom, 509 const SkPaint& paint) { 510 mCanvas->drawRectCoords(left, top, right, bottom, paint); 511 512} 513 514void SkiaCanvas::drawRoundRect(float left, float top, float right, float bottom, 515 float rx, float ry, const SkPaint& paint) { 516 SkRect rect = SkRect::MakeLTRB(left, top, right, bottom); 517 mCanvas->drawRoundRect(rect, rx, ry, paint); 518} 519 520void SkiaCanvas::drawCircle(float x, float y, float radius, const SkPaint& paint) { 521 mCanvas->drawCircle(x, y, radius, paint); 522} 523 524void SkiaCanvas::drawOval(float left, float top, float right, float bottom, const SkPaint& paint) { 525 SkRect oval = SkRect::MakeLTRB(left, top, right, bottom); 526 mCanvas->drawOval(oval, paint); 527} 528 529void SkiaCanvas::drawArc(float left, float top, float right, float bottom, 530 float startAngle, float sweepAngle, bool useCenter, const SkPaint& paint) { 531 SkRect arc = SkRect::MakeLTRB(left, top, right, bottom); 532 mCanvas->drawArc(arc, startAngle, sweepAngle, useCenter, paint); 533} 534 535void SkiaCanvas::drawPath(const SkPath& path, const SkPaint& paint) { 536 mCanvas->drawPath(path, paint); 537} 538 539void SkiaCanvas::drawVertices(SkCanvas::VertexMode vertexMode, int vertexCount, 540 const float* verts, const float* texs, const int* colors, 541 const uint16_t* indices, int indexCount, const SkPaint& paint) { 542#ifndef SK_SCALAR_IS_FLOAT 543 SkDEBUGFAIL("SkScalar must be a float for these conversions to be valid"); 544#endif 545 const int ptCount = vertexCount >> 1; 546 mCanvas->drawVertices(vertexMode, ptCount, (SkPoint*)verts, (SkPoint*)texs, 547 (SkColor*)colors, NULL, indices, indexCount, paint); 548} 549 550// ---------------------------------------------------------------------------- 551// Canvas draw operations: Bitmaps 552// ---------------------------------------------------------------------------- 553 554void SkiaCanvas::drawBitmap(const SkBitmap& bitmap, float left, float top, const SkPaint* paint) { 555 mCanvas->drawBitmap(bitmap, left, top, paint); 556} 557 558void SkiaCanvas::drawBitmap(const SkBitmap& bitmap, const SkMatrix& matrix, const SkPaint* paint) { 559 mCanvas->drawBitmapMatrix(bitmap, matrix, paint); 560} 561 562void SkiaCanvas::drawBitmap(const SkBitmap& bitmap, float srcLeft, float srcTop, 563 float srcRight, float srcBottom, float dstLeft, float dstTop, 564 float dstRight, float dstBottom, const SkPaint* paint) { 565 SkRect srcRect = SkRect::MakeLTRB(srcLeft, srcTop, srcRight, srcBottom); 566 SkRect dstRect = SkRect::MakeLTRB(dstLeft, dstTop, dstRight, dstBottom); 567 mCanvas->drawBitmapRectToRect(bitmap, &srcRect, dstRect, paint); 568} 569 570void SkiaCanvas::drawBitmapMesh(const SkBitmap& bitmap, int meshWidth, int meshHeight, 571 const float* vertices, const int* colors, const SkPaint* paint) { 572 573 const int ptCount = (meshWidth + 1) * (meshHeight + 1); 574 const int indexCount = meshWidth * meshHeight * 6; 575 576 /* Our temp storage holds 2 or 3 arrays. 577 texture points [ptCount * sizeof(SkPoint)] 578 optionally vertex points [ptCount * sizeof(SkPoint)] if we need a 579 copy to convert from float to fixed 580 indices [ptCount * sizeof(uint16_t)] 581 */ 582 ssize_t storageSize = ptCount * sizeof(SkPoint); // texs[] 583 storageSize += indexCount * sizeof(uint16_t); // indices[] 584 585 586#ifndef SK_SCALAR_IS_FLOAT 587 SkDEBUGFAIL("SkScalar must be a float for these conversions to be valid"); 588#endif 589 SkAutoMalloc storage(storageSize); 590 SkPoint* texs = (SkPoint*)storage.get(); 591 uint16_t* indices = (uint16_t*)(texs + ptCount); 592 593 // cons up texture coordinates and indices 594 { 595 const SkScalar w = SkIntToScalar(bitmap.width()); 596 const SkScalar h = SkIntToScalar(bitmap.height()); 597 const SkScalar dx = w / meshWidth; 598 const SkScalar dy = h / meshHeight; 599 600 SkPoint* texsPtr = texs; 601 SkScalar y = 0; 602 for (int i = 0; i <= meshHeight; i++) { 603 if (i == meshHeight) { 604 y = h; // to ensure numerically we hit h exactly 605 } 606 SkScalar x = 0; 607 for (int j = 0; j < meshWidth; j++) { 608 texsPtr->set(x, y); 609 texsPtr += 1; 610 x += dx; 611 } 612 texsPtr->set(w, y); 613 texsPtr += 1; 614 y += dy; 615 } 616 SkASSERT(texsPtr - texs == ptCount); 617 } 618 619 // cons up indices 620 { 621 uint16_t* indexPtr = indices; 622 int index = 0; 623 for (int i = 0; i < meshHeight; i++) { 624 for (int j = 0; j < meshWidth; j++) { 625 // lower-left triangle 626 *indexPtr++ = index; 627 *indexPtr++ = index + meshWidth + 1; 628 *indexPtr++ = index + meshWidth + 2; 629 // upper-right triangle 630 *indexPtr++ = index; 631 *indexPtr++ = index + meshWidth + 2; 632 *indexPtr++ = index + 1; 633 // bump to the next cell 634 index += 1; 635 } 636 // bump to the next row 637 index += 1; 638 } 639 SkASSERT(indexPtr - indices == indexCount); 640 SkASSERT((char*)indexPtr - (char*)storage.get() == storageSize); 641 } 642 643 // double-check that we have legal indices 644#ifdef SK_DEBUG 645 { 646 for (int i = 0; i < indexCount; i++) { 647 SkASSERT((unsigned)indices[i] < (unsigned)ptCount); 648 } 649 } 650#endif 651 652 // cons-up a shader for the bitmap 653 SkPaint tmpPaint; 654 if (paint) { 655 tmpPaint = *paint; 656 } 657 SkShader* shader = SkShader::CreateBitmapShader(bitmap, 658 SkShader::kClamp_TileMode, 659 SkShader::kClamp_TileMode); 660 SkSafeUnref(tmpPaint.setShader(shader)); 661 662 mCanvas->drawVertices(SkCanvas::kTriangles_VertexMode, ptCount, (SkPoint*)vertices, 663 texs, (const SkColor*)colors, NULL, indices, 664 indexCount, tmpPaint); 665} 666 667// ---------------------------------------------------------------------------- 668// Canvas draw operations: Text 669// ---------------------------------------------------------------------------- 670 671class DrawTextFunctor { 672public: 673 DrawTextFunctor(const Layout& layout, SkCanvas* canvas, float x, float y, SkPaint* paint, 674 uint16_t* glyphs, SkPoint* pos) 675 : layout(layout), canvas(canvas), x(x), y(y), paint(paint), glyphs(glyphs), 676 pos(pos) { } 677 678 void operator()(size_t start, size_t end) { 679 for (size_t i = start; i < end; i++) { 680 glyphs[i] = layout.getGlyphId(i); 681 pos[i].fX = x + layout.getX(i); 682 pos[i].fY = y + layout.getY(i); 683 } 684 canvas->drawPosText(glyphs + start, (end - start) << 1, pos + start, *paint); 685 } 686private: 687 const Layout& layout; 688 SkCanvas* canvas; 689 float x; 690 float y; 691 SkPaint* paint; 692 uint16_t* glyphs; 693 SkPoint* pos; 694}; 695 696void SkiaCanvas::drawText(const uint16_t* text, int start, int count, int contextCount, 697 float x, float y, int bidiFlags, const SkPaint& paint, TypefaceImpl* typeface) { 698 Layout layout; 699 std::string css = MinikinUtils::setLayoutProperties(&layout, &paint, bidiFlags, typeface); 700 layout.doLayout(text, start, count, contextCount, css); 701 702 size_t nGlyphs = layout.nGlyphs(); 703 uint16_t* glyphs = new uint16_t[nGlyphs]; 704 SkPoint* pos = new SkPoint[nGlyphs]; 705 706 SkPaint paintCopy(paint); 707 x += MinikinUtils::xOffsetForTextAlign(&paintCopy, layout); 708 paintCopy.setTextAlign(SkPaint::kLeft_Align); 709 paintCopy.setTextEncoding(SkPaint::kGlyphID_TextEncoding); 710 711 DrawTextFunctor f(layout, mCanvas, x, y, &paintCopy, glyphs, pos); 712 MinikinUtils::forFontRun(layout, &paintCopy, f); 713 drawTextDecorations(x, y, layout.getAdvance(), paintCopy); 714 715 delete[] glyphs; 716 delete[] pos; 717} 718 719// Same values used by Skia 720#define kStdStrikeThru_Offset (-6.0f / 21.0f) 721#define kStdUnderline_Offset (1.0f / 9.0f) 722#define kStdUnderline_Thickness (1.0f / 18.0f) 723 724void SkiaCanvas::drawTextDecorations(float x, float y, float length, const SkPaint& paint) { 725 uint32_t flags; 726 SkDrawFilter* drawFilter = mCanvas->getDrawFilter(); 727 if (drawFilter) { 728 SkPaint paintCopy(paint); 729 drawFilter->filter(&paintCopy, SkDrawFilter::kText_Type); 730 flags = paintCopy.getFlags(); 731 } else { 732 flags = paint.getFlags(); 733 } 734 if (flags & (SkPaint::kUnderlineText_Flag | SkPaint::kStrikeThruText_Flag)) { 735 SkScalar left = x; 736 SkScalar right = x + length; 737 float textSize = paint.getTextSize(); 738 float strokeWidth = fmax(textSize * kStdUnderline_Thickness, 1.0f); 739 if (flags & SkPaint::kUnderlineText_Flag) { 740 SkScalar top = y + textSize * kStdUnderline_Offset - 0.5f * strokeWidth; 741 SkScalar bottom = y + textSize * kStdUnderline_Offset + 0.5f * strokeWidth; 742 mCanvas->drawRectCoords(left, top, right, bottom, paint); 743 } 744 if (flags & SkPaint::kStrikeThruText_Flag) { 745 SkScalar top = y + textSize * kStdStrikeThru_Offset - 0.5f * strokeWidth; 746 SkScalar bottom = y + textSize * kStdStrikeThru_Offset + 0.5f * strokeWidth; 747 mCanvas->drawRectCoords(left, top, right, bottom, paint); 748 } 749 } 750} 751 752void SkiaCanvas::drawPosText(const uint16_t* text, const float* positions, int count, int posCount, 753 const SkPaint& paint) { 754 SkPoint* posPtr = posCount > 0 ? new SkPoint[posCount] : NULL; 755 int indx; 756 for (indx = 0; indx < posCount; indx++) { 757 posPtr[indx].fX = positions[indx << 1]; 758 posPtr[indx].fY = positions[(indx << 1) + 1]; 759 } 760 761 SkPaint paintCopy(paint); 762 paintCopy.setTextEncoding(SkPaint::kUTF16_TextEncoding); 763 mCanvas->drawPosText(text, count, posPtr, paintCopy); 764 765 delete[] posPtr; 766} 767 768void SkiaCanvas::drawTextOnPath(const uint16_t* glyphs, int count, const SkPath& path, 769 float hOffset, float vOffset, const SkPaint& paint) { 770 mCanvas->drawTextOnPathHV(glyphs, count, path, hOffset, vOffset, paint); 771} 772 773} // namespace android 774