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