gfx/skia/trunk/src/core/SkPaint.cpp

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

michael@0 1
michael@0 2 /*
michael@0 3 * Copyright 2006 The Android Open Source Project
michael@0 4 *
michael@0 5 * Use of this source code is governed by a BSD-style license that can be
michael@0 6 * found in the LICENSE file.
michael@0 7 */
michael@0 8
michael@0 9 #include "SkPaint.h"
michael@0 10 #include "SkAnnotation.h"
michael@0 11 #include "SkAutoKern.h"
michael@0 12 #include "SkColorFilter.h"
michael@0 13 #include "SkData.h"
michael@0 14 #include "SkDeviceProperties.h"
michael@0 15 #include "SkFontDescriptor.h"
michael@0 16 #include "SkFontHost.h"
michael@0 17 #include "SkGlyphCache.h"
michael@0 18 #include "SkImageFilter.h"
michael@0 19 #include "SkMaskFilter.h"
michael@0 20 #include "SkMaskGamma.h"
michael@0 21 #include "SkReadBuffer.h"
michael@0 22 #include "SkWriteBuffer.h"
michael@0 23 #include "SkPaintDefaults.h"
michael@0 24 #include "SkPaintOptionsAndroid.h"
michael@0 25 #include "SkPathEffect.h"
michael@0 26 #include "SkRasterizer.h"
michael@0 27 #include "SkScalar.h"
michael@0 28 #include "SkScalerContext.h"
michael@0 29 #include "SkShader.h"
michael@0 30 #include "SkStringUtils.h"
michael@0 31 #include "SkStroke.h"
michael@0 32 #include "SkTextFormatParams.h"
michael@0 33 #include "SkTextToPathIter.h"
michael@0 34 #include "SkTLazy.h"
michael@0 35 #include "SkTypeface.h"
michael@0 36 #include "SkXfermode.h"
michael@0 37
michael@0 38 enum {
michael@0 39 kColor_DirtyBit = 1 << 0,
michael@0 40 kBitfields_DirtyBit = 1 << 1,
michael@0 41 kTextSize_DirtyBit = 1 << 2,
michael@0 42 kTextScaleX_DirtyBit = 1 << 3,
michael@0 43 kTextSkewX_DirtyBit = 1 << 4,
michael@0 44 kStrokeWidth_DirtyBit = 1 << 5,
michael@0 45 kStrokeMiter_DirtyBit = 1 << 6,
michael@0 46 kPathEffect_DirtyBit = 1 << 7,
michael@0 47 kShader_DirtyBit = 1 << 8,
michael@0 48 kXfermode_DirtyBit = 1 << 9,
michael@0 49 kMaskFilter_DirtyBit = 1 << 10,
michael@0 50 kColorFilter_DirtyBit = 1 << 11,
michael@0 51 kRasterizer_DirtyBit = 1 << 12,
michael@0 52 kLooper_DirtyBit = 1 << 13,
michael@0 53 kImageFilter_DirtyBit = 1 << 14,
michael@0 54 kTypeface_DirtyBit = 1 << 15,
michael@0 55 kAnnotation_DirtyBit = 1 << 16,
michael@0 56 kPaintOptionsAndroid_DirtyBit = 1 << 17,
michael@0 57 };
michael@0 58
michael@0 59 // define this to get a printf for out-of-range parameter in setters
michael@0 60 // e.g. setTextSize(-1)
michael@0 61 //#define SK_REPORT_API_RANGE_CHECK
michael@0 62
michael@0 63 #ifdef SK_BUILD_FOR_ANDROID
michael@0 64 #define GEN_ID_INC fGenerationID++
michael@0 65 #define GEN_ID_INC_EVAL(expression) if (expression) { fGenerationID++; }
michael@0 66 #else
michael@0 67 #define GEN_ID_INC
michael@0 68 #define GEN_ID_INC_EVAL(expression)
michael@0 69 #endif
michael@0 70
michael@0 71 SkPaint::SkPaint() {
michael@0 72 // since we may have padding, we zero everything so that our memcmp() call
michael@0 73 // in operator== will work correctly.
michael@0 74 // with this, we can skip 0 and null individual initializations
michael@0 75 sk_bzero(this, sizeof(*this));
michael@0 76
michael@0 77 #if 0 // not needed with the bzero call above
michael@0 78 fTypeface = NULL;
michael@0 79 fTextSkewX = 0;
michael@0 80 fPathEffect = NULL;
michael@0 81 fShader = NULL;
michael@0 82 fXfermode = NULL;
michael@0 83 fMaskFilter = NULL;
michael@0 84 fColorFilter = NULL;
michael@0 85 fRasterizer = NULL;
michael@0 86 fLooper = NULL;
michael@0 87 fImageFilter = NULL;
michael@0 88 fAnnotation = NULL;
michael@0 89 fWidth = 0;
michael@0 90 fDirtyBits = 0;
michael@0 91 #endif
michael@0 92
michael@0 93 fTextSize = SkPaintDefaults_TextSize;
michael@0 94 fTextScaleX = SK_Scalar1;
michael@0 95 fColor = SK_ColorBLACK;
michael@0 96 fMiterLimit = SkPaintDefaults_MiterLimit;
michael@0 97 fFlags = SkPaintDefaults_Flags;
michael@0 98 fCapType = kDefault_Cap;
michael@0 99 fJoinType = kDefault_Join;
michael@0 100 fTextAlign = kLeft_Align;
michael@0 101 fStyle = kFill_Style;
michael@0 102 fTextEncoding = kUTF8_TextEncoding;
michael@0 103 fHinting = SkPaintDefaults_Hinting;
michael@0 104 #ifdef SK_BUILD_FOR_ANDROID
michael@0 105 new (&fPaintOptionsAndroid) SkPaintOptionsAndroid;
michael@0 106 fGenerationID = 0;
michael@0 107 #endif
michael@0 108 }
michael@0 109
michael@0 110 SkPaint::SkPaint(const SkPaint& src) {
michael@0 111 memcpy(this, &src, sizeof(src));
michael@0 112
michael@0 113 SkSafeRef(fTypeface);
michael@0 114 SkSafeRef(fPathEffect);
michael@0 115 SkSafeRef(fShader);
michael@0 116 SkSafeRef(fXfermode);
michael@0 117 SkSafeRef(fMaskFilter);
michael@0 118 SkSafeRef(fColorFilter);
michael@0 119 SkSafeRef(fRasterizer);
michael@0 120 SkSafeRef(fLooper);
michael@0 121 SkSafeRef(fImageFilter);
michael@0 122 SkSafeRef(fAnnotation);
michael@0 123
michael@0 124 #ifdef SK_BUILD_FOR_ANDROID
michael@0 125 new (&fPaintOptionsAndroid) SkPaintOptionsAndroid(src.fPaintOptionsAndroid);
michael@0 126 #endif
michael@0 127 }
michael@0 128
michael@0 129 SkPaint::~SkPaint() {
michael@0 130 SkSafeUnref(fTypeface);
michael@0 131 SkSafeUnref(fPathEffect);
michael@0 132 SkSafeUnref(fShader);
michael@0 133 SkSafeUnref(fXfermode);
michael@0 134 SkSafeUnref(fMaskFilter);
michael@0 135 SkSafeUnref(fColorFilter);
michael@0 136 SkSafeUnref(fRasterizer);
michael@0 137 SkSafeUnref(fLooper);
michael@0 138 SkSafeUnref(fImageFilter);
michael@0 139 SkSafeUnref(fAnnotation);
michael@0 140 }
michael@0 141
michael@0 142 SkPaint& SkPaint::operator=(const SkPaint& src) {
michael@0 143 SkASSERT(&src);
michael@0 144
michael@0 145 SkSafeRef(src.fTypeface);
michael@0 146 SkSafeRef(src.fPathEffect);
michael@0 147 SkSafeRef(src.fShader);
michael@0 148 SkSafeRef(src.fXfermode);
michael@0 149 SkSafeRef(src.fMaskFilter);
michael@0 150 SkSafeRef(src.fColorFilter);
michael@0 151 SkSafeRef(src.fRasterizer);
michael@0 152 SkSafeRef(src.fLooper);
michael@0 153 SkSafeRef(src.fImageFilter);
michael@0 154 SkSafeRef(src.fAnnotation);
michael@0 155
michael@0 156 SkSafeUnref(fTypeface);
michael@0 157 SkSafeUnref(fPathEffect);
michael@0 158 SkSafeUnref(fShader);
michael@0 159 SkSafeUnref(fXfermode);
michael@0 160 SkSafeUnref(fMaskFilter);
michael@0 161 SkSafeUnref(fColorFilter);
michael@0 162 SkSafeUnref(fRasterizer);
michael@0 163 SkSafeUnref(fLooper);
michael@0 164 SkSafeUnref(fImageFilter);
michael@0 165 SkSafeUnref(fAnnotation);
michael@0 166
michael@0 167 #ifdef SK_BUILD_FOR_ANDROID
michael@0 168 fPaintOptionsAndroid.~SkPaintOptionsAndroid();
michael@0 169
michael@0 170 uint32_t oldGenerationID = fGenerationID;
michael@0 171 #endif
michael@0 172 memcpy(this, &src, sizeof(src));
michael@0 173 #ifdef SK_BUILD_FOR_ANDROID
michael@0 174 fGenerationID = oldGenerationID + 1;
michael@0 175
michael@0 176 new (&fPaintOptionsAndroid) SkPaintOptionsAndroid(src.fPaintOptionsAndroid);
michael@0 177 #endif
michael@0 178
michael@0 179 return *this;
michael@0 180 }
michael@0 181
michael@0 182 bool operator==(const SkPaint& a, const SkPaint& b) {
michael@0 183 #ifdef SK_BUILD_FOR_ANDROID
michael@0 184 //assumes that fGenerationID is the last field in the struct
michael@0 185 return !memcmp(&a, &b, SK_OFFSETOF(SkPaint, fGenerationID));
michael@0 186 #else
michael@0 187 return !memcmp(&a, &b, sizeof(a));
michael@0 188 #endif
michael@0 189 }
michael@0 190
michael@0 191 void SkPaint::reset() {
michael@0 192 SkPaint init;
michael@0 193
michael@0 194 #ifdef SK_BUILD_FOR_ANDROID
michael@0 195 uint32_t oldGenerationID = fGenerationID;
michael@0 196 #endif
michael@0 197 *this = init;
michael@0 198 #ifdef SK_BUILD_FOR_ANDROID
michael@0 199 fGenerationID = oldGenerationID + 1;
michael@0 200 #endif
michael@0 201 }
michael@0 202
michael@0 203 #ifdef SK_BUILD_FOR_ANDROID
michael@0 204 uint32_t SkPaint::getGenerationID() const {
michael@0 205 return fGenerationID;
michael@0 206 }
michael@0 207
michael@0 208 void SkPaint::setGenerationID(uint32_t generationID) {
michael@0 209 fGenerationID = generationID;
michael@0 210 }
michael@0 211
michael@0 212 unsigned SkPaint::getBaseGlyphCount(SkUnichar text) const {
michael@0 213 SkAutoGlyphCache autoCache(*this, NULL, NULL);
michael@0 214 SkGlyphCache* cache = autoCache.getCache();
michael@0 215 return cache->getBaseGlyphCount(text);
michael@0 216 }
michael@0 217
michael@0 218 void SkPaint::setPaintOptionsAndroid(const SkPaintOptionsAndroid& options) {
michael@0 219 if (options != fPaintOptionsAndroid) {
michael@0 220 fPaintOptionsAndroid = options;
michael@0 221 GEN_ID_INC;
michael@0 222 fDirtyBits |= kPaintOptionsAndroid_DirtyBit;
michael@0 223 }
michael@0 224 }
michael@0 225 #endif
michael@0 226
michael@0 227 SkPaint::FilterLevel SkPaint::getFilterLevel() const {
michael@0 228 int level = 0;
michael@0 229 if (fFlags & kFilterBitmap_Flag) {
michael@0 230 level |= 1;
michael@0 231 }
michael@0 232 if (fFlags & kHighQualityFilterBitmap_Flag) {
michael@0 233 level |= 2;
michael@0 234 }
michael@0 235 return (FilterLevel)level;
michael@0 236 }
michael@0 237
michael@0 238 void SkPaint::setFilterLevel(FilterLevel level) {
michael@0 239 unsigned mask = kFilterBitmap_Flag | kHighQualityFilterBitmap_Flag;
michael@0 240 unsigned flags = 0;
michael@0 241 if (level & 1) {
michael@0 242 flags |= kFilterBitmap_Flag;
michael@0 243 }
michael@0 244 if (level & 2) {
michael@0 245 flags |= kHighQualityFilterBitmap_Flag;
michael@0 246 }
michael@0 247 this->setFlags((fFlags & ~mask) | flags);
michael@0 248 }
michael@0 249
michael@0 250 void SkPaint::setHinting(Hinting hintingLevel) {
michael@0 251 GEN_ID_INC_EVAL((unsigned) hintingLevel != fHinting);
michael@0 252 fHinting = hintingLevel;
michael@0 253 fDirtyBits |= kBitfields_DirtyBit;
michael@0 254 }
michael@0 255
michael@0 256 void SkPaint::setFlags(uint32_t flags) {
michael@0 257 GEN_ID_INC_EVAL(fFlags != flags);
michael@0 258 fFlags = flags;
michael@0 259 fDirtyBits |= kBitfields_DirtyBit;
michael@0 260 }
michael@0 261
michael@0 262 void SkPaint::setAntiAlias(bool doAA) {
michael@0 263 this->setFlags(SkSetClearMask(fFlags, doAA, kAntiAlias_Flag));
michael@0 264 }
michael@0 265
michael@0 266 void SkPaint::setDither(bool doDither) {
michael@0 267 this->setFlags(SkSetClearMask(fFlags, doDither, kDither_Flag));
michael@0 268 }
michael@0 269
michael@0 270 void SkPaint::setSubpixelText(bool doSubpixel) {
michael@0 271 this->setFlags(SkSetClearMask(fFlags, doSubpixel, kSubpixelText_Flag));
michael@0 272 }
michael@0 273
michael@0 274 void SkPaint::setLCDRenderText(bool doLCDRender) {
michael@0 275 this->setFlags(SkSetClearMask(fFlags, doLCDRender, kLCDRenderText_Flag));
michael@0 276 }
michael@0 277
michael@0 278 void SkPaint::setEmbeddedBitmapText(bool doEmbeddedBitmapText) {
michael@0 279 this->setFlags(SkSetClearMask(fFlags, doEmbeddedBitmapText, kEmbeddedBitmapText_Flag));
michael@0 280 }
michael@0 281
michael@0 282 void SkPaint::setAutohinted(bool useAutohinter) {
michael@0 283 this->setFlags(SkSetClearMask(fFlags, useAutohinter, kAutoHinting_Flag));
michael@0 284 }
michael@0 285
michael@0 286 void SkPaint::setLinearText(bool doLinearText) {
michael@0 287 this->setFlags(SkSetClearMask(fFlags, doLinearText, kLinearText_Flag));
michael@0 288 }
michael@0 289
michael@0 290 void SkPaint::setVerticalText(bool doVertical) {
michael@0 291 this->setFlags(SkSetClearMask(fFlags, doVertical, kVerticalText_Flag));
michael@0 292 }
michael@0 293
michael@0 294 void SkPaint::setUnderlineText(bool doUnderline) {
michael@0 295 this->setFlags(SkSetClearMask(fFlags, doUnderline, kUnderlineText_Flag));
michael@0 296 }
michael@0 297
michael@0 298 void SkPaint::setStrikeThruText(bool doStrikeThru) {
michael@0 299 this->setFlags(SkSetClearMask(fFlags, doStrikeThru, kStrikeThruText_Flag));
michael@0 300 }
michael@0 301
michael@0 302 void SkPaint::setFakeBoldText(bool doFakeBold) {
michael@0 303 this->setFlags(SkSetClearMask(fFlags, doFakeBold, kFakeBoldText_Flag));
michael@0 304 }
michael@0 305
michael@0 306 void SkPaint::setDevKernText(bool doDevKern) {
michael@0 307 this->setFlags(SkSetClearMask(fFlags, doDevKern, kDevKernText_Flag));
michael@0 308 }
michael@0 309
michael@0 310 void SkPaint::setDistanceFieldTextTEMP(bool doDistanceFieldText) {
michael@0 311 this->setFlags(SkSetClearMask(fFlags, doDistanceFieldText, kDistanceFieldTextTEMP_Flag));
michael@0 312 }
michael@0 313
michael@0 314 void SkPaint::setStyle(Style style) {
michael@0 315 if ((unsigned)style < kStyleCount) {
michael@0 316 GEN_ID_INC_EVAL((unsigned)style != fStyle);
michael@0 317 fStyle = style;
michael@0 318 fDirtyBits |= kBitfields_DirtyBit;
michael@0 319 } else {
michael@0 320 #ifdef SK_REPORT_API_RANGE_CHECK
michael@0 321 SkDebugf("SkPaint::setStyle(%d) out of range\n", style);
michael@0 322 #endif
michael@0 323 }
michael@0 324 }
michael@0 325
michael@0 326 void SkPaint::setColor(SkColor color) {
michael@0 327 GEN_ID_INC_EVAL(color != fColor);
michael@0 328 fColor = color;
michael@0 329 fDirtyBits |= kColor_DirtyBit;
michael@0 330 }
michael@0 331
michael@0 332 void SkPaint::setAlpha(U8CPU a) {
michael@0 333 this->setColor(SkColorSetARGB(a, SkColorGetR(fColor),
michael@0 334 SkColorGetG(fColor), SkColorGetB(fColor)));
michael@0 335 }
michael@0 336
michael@0 337 void SkPaint::setARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b) {
michael@0 338 this->setColor(SkColorSetARGB(a, r, g, b));
michael@0 339 }
michael@0 340
michael@0 341 void SkPaint::setStrokeWidth(SkScalar width) {
michael@0 342 if (width >= 0) {
michael@0 343 GEN_ID_INC_EVAL(width != fWidth);
michael@0 344 fWidth = width;
michael@0 345 fDirtyBits |= kStrokeWidth_DirtyBit;
michael@0 346 } else {
michael@0 347 #ifdef SK_REPORT_API_RANGE_CHECK
michael@0 348 SkDebugf("SkPaint::setStrokeWidth() called with negative value\n");
michael@0 349 #endif
michael@0 350 }
michael@0 351 }
michael@0 352
michael@0 353 void SkPaint::setStrokeMiter(SkScalar limit) {
michael@0 354 if (limit >= 0) {
michael@0 355 GEN_ID_INC_EVAL(limit != fMiterLimit);
michael@0 356 fMiterLimit = limit;
michael@0 357 fDirtyBits |= kStrokeMiter_DirtyBit;
michael@0 358 } else {
michael@0 359 #ifdef SK_REPORT_API_RANGE_CHECK
michael@0 360 SkDebugf("SkPaint::setStrokeMiter() called with negative value\n");
michael@0 361 #endif
michael@0 362 }
michael@0 363 }
michael@0 364
michael@0 365 void SkPaint::setStrokeCap(Cap ct) {
michael@0 366 if ((unsigned)ct < kCapCount) {
michael@0 367 GEN_ID_INC_EVAL((unsigned)ct != fCapType);
michael@0 368 fCapType = SkToU8(ct);
michael@0 369 fDirtyBits |= kBitfields_DirtyBit;
michael@0 370 } else {
michael@0 371 #ifdef SK_REPORT_API_RANGE_CHECK
michael@0 372 SkDebugf("SkPaint::setStrokeCap(%d) out of range\n", ct);
michael@0 373 #endif
michael@0 374 }
michael@0 375 }
michael@0 376
michael@0 377 void SkPaint::setStrokeJoin(Join jt) {
michael@0 378 if ((unsigned)jt < kJoinCount) {
michael@0 379 GEN_ID_INC_EVAL((unsigned)jt != fJoinType);
michael@0 380 fJoinType = SkToU8(jt);
michael@0 381 fDirtyBits |= kBitfields_DirtyBit;
michael@0 382 } else {
michael@0 383 #ifdef SK_REPORT_API_RANGE_CHECK
michael@0 384 SkDebugf("SkPaint::setStrokeJoin(%d) out of range\n", jt);
michael@0 385 #endif
michael@0 386 }
michael@0 387 }
michael@0 388
michael@0 389 ///////////////////////////////////////////////////////////////////////////////
michael@0 390
michael@0 391 void SkPaint::setTextAlign(Align align) {
michael@0 392 if ((unsigned)align < kAlignCount) {
michael@0 393 GEN_ID_INC_EVAL((unsigned)align != fTextAlign);
michael@0 394 fTextAlign = SkToU8(align);
michael@0 395 fDirtyBits |= kBitfields_DirtyBit;
michael@0 396 } else {
michael@0 397 #ifdef SK_REPORT_API_RANGE_CHECK
michael@0 398 SkDebugf("SkPaint::setTextAlign(%d) out of range\n", align);
michael@0 399 #endif
michael@0 400 }
michael@0 401 }
michael@0 402
michael@0 403 void SkPaint::setTextSize(SkScalar ts) {
michael@0 404 if (ts >= 0) {
michael@0 405 GEN_ID_INC_EVAL(ts != fTextSize);
michael@0 406 fTextSize = ts;
michael@0 407 fDirtyBits |= kTextSize_DirtyBit;
michael@0 408 } else {
michael@0 409 #ifdef SK_REPORT_API_RANGE_CHECK
michael@0 410 SkDebugf("SkPaint::setTextSize() called with negative value\n");
michael@0 411 #endif
michael@0 412 }
michael@0 413 }
michael@0 414
michael@0 415 void SkPaint::setTextScaleX(SkScalar scaleX) {
michael@0 416 GEN_ID_INC_EVAL(scaleX != fTextScaleX);
michael@0 417 fTextScaleX = scaleX;
michael@0 418 fDirtyBits |= kTextScaleX_DirtyBit;
michael@0 419 }
michael@0 420
michael@0 421 void SkPaint::setTextSkewX(SkScalar skewX) {
michael@0 422 GEN_ID_INC_EVAL(skewX != fTextSkewX);
michael@0 423 fTextSkewX = skewX;
michael@0 424 fDirtyBits |= kTextSkewX_DirtyBit;
michael@0 425 }
michael@0 426
michael@0 427 void SkPaint::setTextEncoding(TextEncoding encoding) {
michael@0 428 if ((unsigned)encoding <= kGlyphID_TextEncoding) {
michael@0 429 GEN_ID_INC_EVAL((unsigned)encoding != fTextEncoding);
michael@0 430 fTextEncoding = encoding;
michael@0 431 fDirtyBits |= kBitfields_DirtyBit;
michael@0 432 } else {
michael@0 433 #ifdef SK_REPORT_API_RANGE_CHECK
michael@0 434 SkDebugf("SkPaint::setTextEncoding(%d) out of range\n", encoding);
michael@0 435 #endif
michael@0 436 }
michael@0 437 }
michael@0 438
michael@0 439 ///////////////////////////////////////////////////////////////////////////////
michael@0 440
michael@0 441 // Returns dst with the given bitmask enabled or disabled, depending on value.
michael@0 442 inline static uint32_t set_mask(uint32_t dst, uint32_t bitmask, bool value) {
michael@0 443 return value ? (dst | bitmask) : (dst & ~bitmask);
michael@0 444 }
michael@0 445
michael@0 446 SkTypeface* SkPaint::setTypeface(SkTypeface* font) {
michael@0 447 SkRefCnt_SafeAssign(fTypeface, font);
michael@0 448 GEN_ID_INC;
michael@0 449 fDirtyBits = set_mask(fDirtyBits, kTypeface_DirtyBit, font != NULL);
michael@0 450 return font;
michael@0 451 }
michael@0 452
michael@0 453 SkRasterizer* SkPaint::setRasterizer(SkRasterizer* r) {
michael@0 454 SkRefCnt_SafeAssign(fRasterizer, r);
michael@0 455 GEN_ID_INC;
michael@0 456 fDirtyBits = set_mask(fDirtyBits, kRasterizer_DirtyBit, r != NULL);
michael@0 457 return r;
michael@0 458 }
michael@0 459
michael@0 460 SkDrawLooper* SkPaint::setLooper(SkDrawLooper* looper) {
michael@0 461 SkRefCnt_SafeAssign(fLooper, looper);
michael@0 462 GEN_ID_INC;
michael@0 463 fDirtyBits = set_mask(fDirtyBits, kLooper_DirtyBit, looper != NULL);
michael@0 464 return looper;
michael@0 465 }
michael@0 466
michael@0 467 SkImageFilter* SkPaint::setImageFilter(SkImageFilter* imageFilter) {
michael@0 468 SkRefCnt_SafeAssign(fImageFilter, imageFilter);
michael@0 469 GEN_ID_INC;
michael@0 470 fDirtyBits = set_mask(fDirtyBits, kImageFilter_DirtyBit, imageFilter != NULL);
michael@0 471 return imageFilter;
michael@0 472 }
michael@0 473
michael@0 474 SkAnnotation* SkPaint::setAnnotation(SkAnnotation* annotation) {
michael@0 475 SkRefCnt_SafeAssign(fAnnotation, annotation);
michael@0 476 GEN_ID_INC;
michael@0 477 fDirtyBits = set_mask(fDirtyBits, kAnnotation_DirtyBit, annotation != NULL);
michael@0 478 return annotation;
michael@0 479 }
michael@0 480
michael@0 481 ///////////////////////////////////////////////////////////////////////////////
michael@0 482
michael@0 483 static SkScalar mag2(SkScalar x, SkScalar y) {
michael@0 484 return x * x + y * y;
michael@0 485 }
michael@0 486
michael@0 487 static bool tooBig(const SkMatrix& m, SkScalar ma2max) {
michael@0 488 return mag2(m[SkMatrix::kMScaleX], m[SkMatrix::kMSkewY]) > ma2max
michael@0 489 ||
michael@0 490 mag2(m[SkMatrix::kMSkewX], m[SkMatrix::kMScaleY]) > ma2max;
michael@0 491 }
michael@0 492
michael@0 493 bool SkPaint::TooBigToUseCache(const SkMatrix& ctm, const SkMatrix& textM) {
michael@0 494 SkASSERT(!ctm.hasPerspective());
michael@0 495 SkASSERT(!textM.hasPerspective());
michael@0 496
michael@0 497 SkMatrix matrix;
michael@0 498 matrix.setConcat(ctm, textM);
michael@0 499 return tooBig(matrix, MaxCacheSize2());
michael@0 500 }
michael@0 501
michael@0 502 bool SkPaint::tooBigToUseCache(const SkMatrix& ctm) const {
michael@0 503 SkMatrix textM;
michael@0 504 return TooBigToUseCache(ctm, *this->setTextMatrix(&textM));
michael@0 505 }
michael@0 506
michael@0 507 bool SkPaint::tooBigToUseCache() const {
michael@0 508 SkMatrix textM;
michael@0 509 return tooBig(*this->setTextMatrix(&textM), MaxCacheSize2());
michael@0 510 }
michael@0 511
michael@0 512 ///////////////////////////////////////////////////////////////////////////////
michael@0 513
michael@0 514 #include "SkGlyphCache.h"
michael@0 515 #include "SkUtils.h"
michael@0 516
michael@0 517 static void DetachDescProc(SkTypeface* typeface, const SkDescriptor* desc,
michael@0 518 void* context) {
michael@0 519 *((SkGlyphCache**)context) = SkGlyphCache::DetachCache(typeface, desc);
michael@0 520 }
michael@0 521
michael@0 522 int SkPaint::textToGlyphs(const void* textData, size_t byteLength,
michael@0 523 uint16_t glyphs[]) const {
michael@0 524 if (byteLength == 0) {
michael@0 525 return 0;
michael@0 526 }
michael@0 527
michael@0 528 SkASSERT(textData != NULL);
michael@0 529
michael@0 530 if (NULL == glyphs) {
michael@0 531 switch (this->getTextEncoding()) {
michael@0 532 case kUTF8_TextEncoding:
michael@0 533 return SkUTF8_CountUnichars((const char*)textData, byteLength);
michael@0 534 case kUTF16_TextEncoding:
michael@0 535 return SkUTF16_CountUnichars((const uint16_t*)textData,
michael@0 536 byteLength >> 1);
michael@0 537 case kUTF32_TextEncoding:
michael@0 538 return byteLength >> 2;
michael@0 539 case kGlyphID_TextEncoding:
michael@0 540 return byteLength >> 1;
michael@0 541 default:
michael@0 542 SkDEBUGFAIL("unknown text encoding");
michael@0 543 }
michael@0 544 return 0;
michael@0 545 }
michael@0 546
michael@0 547 // if we get here, we have a valid glyphs[] array, so time to fill it in
michael@0 548
michael@0 549 // handle this encoding before the setup for the glyphcache
michael@0 550 if (this->getTextEncoding() == kGlyphID_TextEncoding) {
michael@0 551 // we want to ignore the low bit of byteLength
michael@0 552 memcpy(glyphs, textData, byteLength >> 1 << 1);
michael@0 553 return byteLength >> 1;
michael@0 554 }
michael@0 555
michael@0 556 SkAutoGlyphCache autoCache(*this, NULL, NULL);
michael@0 557 SkGlyphCache* cache = autoCache.getCache();
michael@0 558
michael@0 559 const char* text = (const char*)textData;
michael@0 560 const char* stop = text + byteLength;
michael@0 561 uint16_t* gptr = glyphs;
michael@0 562
michael@0 563 switch (this->getTextEncoding()) {
michael@0 564 case SkPaint::kUTF8_TextEncoding:
michael@0 565 while (text < stop) {
michael@0 566 *gptr++ = cache->unicharToGlyph(SkUTF8_NextUnichar(&text));
michael@0 567 }
michael@0 568 break;
michael@0 569 case SkPaint::kUTF16_TextEncoding: {
michael@0 570 const uint16_t* text16 = (const uint16_t*)text;
michael@0 571 const uint16_t* stop16 = (const uint16_t*)stop;
michael@0 572 while (text16 < stop16) {
michael@0 573 *gptr++ = cache->unicharToGlyph(SkUTF16_NextUnichar(&text16));
michael@0 574 }
michael@0 575 break;
michael@0 576 }
michael@0 577 case kUTF32_TextEncoding: {
michael@0 578 const int32_t* text32 = (const int32_t*)text;
michael@0 579 const int32_t* stop32 = (const int32_t*)stop;
michael@0 580 while (text32 < stop32) {
michael@0 581 *gptr++ = cache->unicharToGlyph(*text32++);
michael@0 582 }
michael@0 583 break;
michael@0 584 }
michael@0 585 default:
michael@0 586 SkDEBUGFAIL("unknown text encoding");
michael@0 587 }
michael@0 588 return gptr - glyphs;
michael@0 589 }
michael@0 590
michael@0 591 bool SkPaint::containsText(const void* textData, size_t byteLength) const {
michael@0 592 if (0 == byteLength) {
michael@0 593 return true;
michael@0 594 }
michael@0 595
michael@0 596 SkASSERT(textData != NULL);
michael@0 597
michael@0 598 // handle this encoding before the setup for the glyphcache
michael@0 599 if (this->getTextEncoding() == kGlyphID_TextEncoding) {
michael@0 600 const uint16_t* glyphID = static_cast<const uint16_t*>(textData);
michael@0 601 size_t count = byteLength >> 1;
michael@0 602 for (size_t i = 0; i < count; i++) {
michael@0 603 if (0 == glyphID[i]) {
michael@0 604 return false;
michael@0 605 }
michael@0 606 }
michael@0 607 return true;
michael@0 608 }
michael@0 609
michael@0 610 SkAutoGlyphCache autoCache(*this, NULL, NULL);
michael@0 611 SkGlyphCache* cache = autoCache.getCache();
michael@0 612
michael@0 613 switch (this->getTextEncoding()) {
michael@0 614 case SkPaint::kUTF8_TextEncoding: {
michael@0 615 const char* text = static_cast<const char*>(textData);
michael@0 616 const char* stop = text + byteLength;
michael@0 617 while (text < stop) {
michael@0 618 if (0 == cache->unicharToGlyph(SkUTF8_NextUnichar(&text))) {
michael@0 619 return false;
michael@0 620 }
michael@0 621 }
michael@0 622 break;
michael@0 623 }
michael@0 624 case SkPaint::kUTF16_TextEncoding: {
michael@0 625 const uint16_t* text = static_cast<const uint16_t*>(textData);
michael@0 626 const uint16_t* stop = text + (byteLength >> 1);
michael@0 627 while (text < stop) {
michael@0 628 if (0 == cache->unicharToGlyph(SkUTF16_NextUnichar(&text))) {
michael@0 629 return false;
michael@0 630 }
michael@0 631 }
michael@0 632 break;
michael@0 633 }
michael@0 634 case SkPaint::kUTF32_TextEncoding: {
michael@0 635 const int32_t* text = static_cast<const int32_t*>(textData);
michael@0 636 const int32_t* stop = text + (byteLength >> 2);
michael@0 637 while (text < stop) {
michael@0 638 if (0 == cache->unicharToGlyph(*text++)) {
michael@0 639 return false;
michael@0 640 }
michael@0 641 }
michael@0 642 break;
michael@0 643 }
michael@0 644 default:
michael@0 645 SkDEBUGFAIL("unknown text encoding");
michael@0 646 return false;
michael@0 647 }
michael@0 648 return true;
michael@0 649 }
michael@0 650
michael@0 651 void SkPaint::glyphsToUnichars(const uint16_t glyphs[], int count,
michael@0 652 SkUnichar textData[]) const {
michael@0 653 if (count <= 0) {
michael@0 654 return;
michael@0 655 }
michael@0 656
michael@0 657 SkASSERT(glyphs != NULL);
michael@0 658 SkASSERT(textData != NULL);
michael@0 659
michael@0 660 SkAutoGlyphCache autoCache(*this, NULL, NULL);
michael@0 661 SkGlyphCache* cache = autoCache.getCache();
michael@0 662
michael@0 663 for (int index = 0; index < count; index++) {
michael@0 664 textData[index] = cache->glyphToUnichar(glyphs[index]);
michael@0 665 }
michael@0 666 }
michael@0 667
michael@0 668 ///////////////////////////////////////////////////////////////////////////////
michael@0 669
michael@0 670 static const SkGlyph& sk_getMetrics_utf8_next(SkGlyphCache* cache,
michael@0 671 const char** text) {
michael@0 672 SkASSERT(cache != NULL);
michael@0 673 SkASSERT(text != NULL);
michael@0 674
michael@0 675 return cache->getUnicharMetrics(SkUTF8_NextUnichar(text));
michael@0 676 }
michael@0 677
michael@0 678 static const SkGlyph& sk_getMetrics_utf8_prev(SkGlyphCache* cache,
michael@0 679 const char** text) {
michael@0 680 SkASSERT(cache != NULL);
michael@0 681 SkASSERT(text != NULL);
michael@0 682
michael@0 683 return cache->getUnicharMetrics(SkUTF8_PrevUnichar(text));
michael@0 684 }
michael@0 685
michael@0 686 static const SkGlyph& sk_getMetrics_utf16_next(SkGlyphCache* cache,
michael@0 687 const char** text) {
michael@0 688 SkASSERT(cache != NULL);
michael@0 689 SkASSERT(text != NULL);
michael@0 690
michael@0 691 return cache->getUnicharMetrics(SkUTF16_NextUnichar((const uint16_t**)text));
michael@0 692 }
michael@0 693
michael@0 694 static const SkGlyph& sk_getMetrics_utf16_prev(SkGlyphCache* cache,
michael@0 695 const char** text) {
michael@0 696 SkASSERT(cache != NULL);
michael@0 697 SkASSERT(text != NULL);
michael@0 698
michael@0 699 return cache->getUnicharMetrics(SkUTF16_PrevUnichar((const uint16_t**)text));
michael@0 700 }
michael@0 701
michael@0 702 static const SkGlyph& sk_getMetrics_utf32_next(SkGlyphCache* cache,
michael@0 703 const char** text) {
michael@0 704 SkASSERT(cache != NULL);
michael@0 705 SkASSERT(text != NULL);
michael@0 706
michael@0 707 const int32_t* ptr = *(const int32_t**)text;
michael@0 708 SkUnichar uni = *ptr++;
michael@0 709 *text = (const char*)ptr;
michael@0 710 return cache->getUnicharMetrics(uni);
michael@0 711 }
michael@0 712
michael@0 713 static const SkGlyph& sk_getMetrics_utf32_prev(SkGlyphCache* cache,
michael@0 714 const char** text) {
michael@0 715 SkASSERT(cache != NULL);
michael@0 716 SkASSERT(text != NULL);
michael@0 717
michael@0 718 const int32_t* ptr = *(const int32_t**)text;
michael@0 719 SkUnichar uni = *--ptr;
michael@0 720 *text = (const char*)ptr;
michael@0 721 return cache->getUnicharMetrics(uni);
michael@0 722 }
michael@0 723
michael@0 724 static const SkGlyph& sk_getMetrics_glyph_next(SkGlyphCache* cache,
michael@0 725 const char** text) {
michael@0 726 SkASSERT(cache != NULL);
michael@0 727 SkASSERT(text != NULL);
michael@0 728
michael@0 729 const uint16_t* ptr = *(const uint16_t**)text;
michael@0 730 unsigned glyphID = *ptr;
michael@0 731 ptr += 1;
michael@0 732 *text = (const char*)ptr;
michael@0 733 return cache->getGlyphIDMetrics(glyphID);
michael@0 734 }
michael@0 735
michael@0 736 static const SkGlyph& sk_getMetrics_glyph_prev(SkGlyphCache* cache,
michael@0 737 const char** text) {
michael@0 738 SkASSERT(cache != NULL);
michael@0 739 SkASSERT(text != NULL);
michael@0 740
michael@0 741 const uint16_t* ptr = *(const uint16_t**)text;
michael@0 742 ptr -= 1;
michael@0 743 unsigned glyphID = *ptr;
michael@0 744 *text = (const char*)ptr;
michael@0 745 return cache->getGlyphIDMetrics(glyphID);
michael@0 746 }
michael@0 747
michael@0 748 static const SkGlyph& sk_getAdvance_utf8_next(SkGlyphCache* cache,
michael@0 749 const char** text) {
michael@0 750 SkASSERT(cache != NULL);
michael@0 751 SkASSERT(text != NULL);
michael@0 752
michael@0 753 return cache->getUnicharAdvance(SkUTF8_NextUnichar(text));
michael@0 754 }
michael@0 755
michael@0 756 static const SkGlyph& sk_getAdvance_utf8_prev(SkGlyphCache* cache,
michael@0 757 const char** text) {
michael@0 758 SkASSERT(cache != NULL);
michael@0 759 SkASSERT(text != NULL);
michael@0 760
michael@0 761 return cache->getUnicharAdvance(SkUTF8_PrevUnichar(text));
michael@0 762 }
michael@0 763
michael@0 764 static const SkGlyph& sk_getAdvance_utf16_next(SkGlyphCache* cache,
michael@0 765 const char** text) {
michael@0 766 SkASSERT(cache != NULL);
michael@0 767 SkASSERT(text != NULL);
michael@0 768
michael@0 769 return cache->getUnicharAdvance(SkUTF16_NextUnichar((const uint16_t**)text));
michael@0 770 }
michael@0 771
michael@0 772 static const SkGlyph& sk_getAdvance_utf16_prev(SkGlyphCache* cache,
michael@0 773 const char** text) {
michael@0 774 SkASSERT(cache != NULL);
michael@0 775 SkASSERT(text != NULL);
michael@0 776
michael@0 777 return cache->getUnicharAdvance(SkUTF16_PrevUnichar((const uint16_t**)text));
michael@0 778 }
michael@0 779
michael@0 780 static const SkGlyph& sk_getAdvance_utf32_next(SkGlyphCache* cache,
michael@0 781 const char** text) {
michael@0 782 SkASSERT(cache != NULL);
michael@0 783 SkASSERT(text != NULL);
michael@0 784
michael@0 785 const int32_t* ptr = *(const int32_t**)text;
michael@0 786 SkUnichar uni = *ptr++;
michael@0 787 *text = (const char*)ptr;
michael@0 788 return cache->getUnicharAdvance(uni);
michael@0 789 }
michael@0 790
michael@0 791 static const SkGlyph& sk_getAdvance_utf32_prev(SkGlyphCache* cache,
michael@0 792 const char** text) {
michael@0 793 SkASSERT(cache != NULL);
michael@0 794 SkASSERT(text != NULL);
michael@0 795
michael@0 796 const int32_t* ptr = *(const int32_t**)text;
michael@0 797 SkUnichar uni = *--ptr;
michael@0 798 *text = (const char*)ptr;
michael@0 799 return cache->getUnicharAdvance(uni);
michael@0 800 }
michael@0 801
michael@0 802 static const SkGlyph& sk_getAdvance_glyph_next(SkGlyphCache* cache,
michael@0 803 const char** text) {
michael@0 804 SkASSERT(cache != NULL);
michael@0 805 SkASSERT(text != NULL);
michael@0 806
michael@0 807 const uint16_t* ptr = *(const uint16_t**)text;
michael@0 808 unsigned glyphID = *ptr;
michael@0 809 ptr += 1;
michael@0 810 *text = (const char*)ptr;
michael@0 811 return cache->getGlyphIDAdvance(glyphID);
michael@0 812 }
michael@0 813
michael@0 814 static const SkGlyph& sk_getAdvance_glyph_prev(SkGlyphCache* cache,
michael@0 815 const char** text) {
michael@0 816 SkASSERT(cache != NULL);
michael@0 817 SkASSERT(text != NULL);
michael@0 818
michael@0 819 const uint16_t* ptr = *(const uint16_t**)text;
michael@0 820 ptr -= 1;
michael@0 821 unsigned glyphID = *ptr;
michael@0 822 *text = (const char*)ptr;
michael@0 823 return cache->getGlyphIDAdvance(glyphID);
michael@0 824 }
michael@0 825
michael@0 826 SkMeasureCacheProc SkPaint::getMeasureCacheProc(TextBufferDirection tbd,
michael@0 827 bool needFullMetrics) const {
michael@0 828 static const SkMeasureCacheProc gMeasureCacheProcs[] = {
michael@0 829 sk_getMetrics_utf8_next,
michael@0 830 sk_getMetrics_utf16_next,
michael@0 831 sk_getMetrics_utf32_next,
michael@0 832 sk_getMetrics_glyph_next,
michael@0 833
michael@0 834 sk_getMetrics_utf8_prev,
michael@0 835 sk_getMetrics_utf16_prev,
michael@0 836 sk_getMetrics_utf32_prev,
michael@0 837 sk_getMetrics_glyph_prev,
michael@0 838
michael@0 839 sk_getAdvance_utf8_next,
michael@0 840 sk_getAdvance_utf16_next,
michael@0 841 sk_getAdvance_utf32_next,
michael@0 842 sk_getAdvance_glyph_next,
michael@0 843
michael@0 844 sk_getAdvance_utf8_prev,
michael@0 845 sk_getAdvance_utf16_prev,
michael@0 846 sk_getAdvance_utf32_prev,
michael@0 847 sk_getAdvance_glyph_prev
michael@0 848 };
michael@0 849
michael@0 850 unsigned index = this->getTextEncoding();
michael@0 851
michael@0 852 if (kBackward_TextBufferDirection == tbd) {
michael@0 853 index += 4;
michael@0 854 }
michael@0 855 if (!needFullMetrics && !this->isDevKernText()) {
michael@0 856 index += 8;
michael@0 857 }
michael@0 858
michael@0 859 SkASSERT(index < SK_ARRAY_COUNT(gMeasureCacheProcs));
michael@0 860 return gMeasureCacheProcs[index];
michael@0 861 }
michael@0 862
michael@0 863 ///////////////////////////////////////////////////////////////////////////////
michael@0 864
michael@0 865 static const SkGlyph& sk_getMetrics_utf8_00(SkGlyphCache* cache,
michael@0 866 const char** text, SkFixed, SkFixed) {
michael@0 867 SkASSERT(cache != NULL);
michael@0 868 SkASSERT(text != NULL);
michael@0 869
michael@0 870 return cache->getUnicharMetrics(SkUTF8_NextUnichar(text));
michael@0 871 }
michael@0 872
michael@0 873 static const SkGlyph& sk_getMetrics_utf8_xy(SkGlyphCache* cache,
michael@0 874 const char** text, SkFixed x, SkFixed y) {
michael@0 875 SkASSERT(cache != NULL);
michael@0 876 SkASSERT(text != NULL);
michael@0 877
michael@0 878 return cache->getUnicharMetrics(SkUTF8_NextUnichar(text), x, y);
michael@0 879 }
michael@0 880
michael@0 881 static const SkGlyph& sk_getMetrics_utf16_00(SkGlyphCache* cache,
michael@0 882 const char** text, SkFixed, SkFixed) {
michael@0 883 SkASSERT(cache != NULL);
michael@0 884 SkASSERT(text != NULL);
michael@0 885
michael@0 886 return cache->getUnicharMetrics(SkUTF16_NextUnichar((const uint16_t**)text));
michael@0 887 }
michael@0 888
michael@0 889 static const SkGlyph& sk_getMetrics_utf16_xy(SkGlyphCache* cache,
michael@0 890 const char** text, SkFixed x, SkFixed y) {
michael@0 891 SkASSERT(cache != NULL);
michael@0 892 SkASSERT(text != NULL);
michael@0 893
michael@0 894 return cache->getUnicharMetrics(SkUTF16_NextUnichar((const uint16_t**)text),
michael@0 895 x, y);
michael@0 896 }
michael@0 897
michael@0 898 static const SkGlyph& sk_getMetrics_utf32_00(SkGlyphCache* cache,
michael@0 899 const char** text, SkFixed, SkFixed) {
michael@0 900 SkASSERT(cache != NULL);
michael@0 901 SkASSERT(text != NULL);
michael@0 902
michael@0 903 const int32_t* ptr = *(const int32_t**)text;
michael@0 904 SkUnichar uni = *ptr++;
michael@0 905 *text = (const char*)ptr;
michael@0 906 return cache->getUnicharMetrics(uni);
michael@0 907 }
michael@0 908
michael@0 909 static const SkGlyph& sk_getMetrics_utf32_xy(SkGlyphCache* cache,
michael@0 910 const char** text, SkFixed x, SkFixed y) {
michael@0 911 SkASSERT(cache != NULL);
michael@0 912 SkASSERT(text != NULL);
michael@0 913
michael@0 914 const int32_t* ptr = *(const int32_t**)text;
michael@0 915 SkUnichar uni = *--ptr;
michael@0 916 *text = (const char*)ptr;
michael@0 917 return cache->getUnicharMetrics(uni, x, y);
michael@0 918 }
michael@0 919
michael@0 920 static const SkGlyph& sk_getMetrics_glyph_00(SkGlyphCache* cache,
michael@0 921 const char** text, SkFixed, SkFixed) {
michael@0 922 SkASSERT(cache != NULL);
michael@0 923 SkASSERT(text != NULL);
michael@0 924
michael@0 925 const uint16_t* ptr = *(const uint16_t**)text;
michael@0 926 unsigned glyphID = *ptr;
michael@0 927 ptr += 1;
michael@0 928 *text = (const char*)ptr;
michael@0 929 return cache->getGlyphIDMetrics(glyphID);
michael@0 930 }
michael@0 931
michael@0 932 static const SkGlyph& sk_getMetrics_glyph_xy(SkGlyphCache* cache,
michael@0 933 const char** text, SkFixed x, SkFixed y) {
michael@0 934 SkASSERT(cache != NULL);
michael@0 935 SkASSERT(text != NULL);
michael@0 936
michael@0 937 const uint16_t* ptr = *(const uint16_t**)text;
michael@0 938 unsigned glyphID = *ptr;
michael@0 939 ptr += 1;
michael@0 940 *text = (const char*)ptr;
michael@0 941 return cache->getGlyphIDMetrics(glyphID, x, y);
michael@0 942 }
michael@0 943
michael@0 944 SkDrawCacheProc SkPaint::getDrawCacheProc() const {
michael@0 945 static const SkDrawCacheProc gDrawCacheProcs[] = {
michael@0 946 sk_getMetrics_utf8_00,
michael@0 947 sk_getMetrics_utf16_00,
michael@0 948 sk_getMetrics_utf32_00,
michael@0 949 sk_getMetrics_glyph_00,
michael@0 950
michael@0 951 sk_getMetrics_utf8_xy,
michael@0 952 sk_getMetrics_utf16_xy,
michael@0 953 sk_getMetrics_utf32_xy,
michael@0 954 sk_getMetrics_glyph_xy
michael@0 955 };
michael@0 956
michael@0 957 unsigned index = this->getTextEncoding();
michael@0 958 if (fFlags & kSubpixelText_Flag) {
michael@0 959 index += 4;
michael@0 960 }
michael@0 961
michael@0 962 SkASSERT(index < SK_ARRAY_COUNT(gDrawCacheProcs));
michael@0 963 return gDrawCacheProcs[index];
michael@0 964 }
michael@0 965
michael@0 966 ///////////////////////////////////////////////////////////////////////////////
michael@0 967
michael@0 968 #define TEXT_AS_PATHS_PAINT_FLAGS_TO_IGNORE ( \
michael@0 969 SkPaint::kDevKernText_Flag | \
michael@0 970 SkPaint::kLinearText_Flag | \
michael@0 971 SkPaint::kLCDRenderText_Flag | \
michael@0 972 SkPaint::kEmbeddedBitmapText_Flag | \
michael@0 973 SkPaint::kAutoHinting_Flag | \
michael@0 974 SkPaint::kGenA8FromLCD_Flag )
michael@0 975
michael@0 976 SkScalar SkPaint::setupForAsPaths() {
michael@0 977 uint32_t flags = this->getFlags();
michael@0 978 // clear the flags we don't care about
michael@0 979 flags &= ~TEXT_AS_PATHS_PAINT_FLAGS_TO_IGNORE;
michael@0 980 // set the flags we do care about
michael@0 981 flags |= SkPaint::kSubpixelText_Flag;
michael@0 982
michael@0 983 this->setFlags(flags);
michael@0 984 this->setHinting(SkPaint::kNo_Hinting);
michael@0 985
michael@0 986 SkScalar textSize = fTextSize;
michael@0 987 this->setTextSize(kCanonicalTextSizeForPaths);
michael@0 988 return textSize / kCanonicalTextSizeForPaths;
michael@0 989 }
michael@0 990
michael@0 991 class SkCanonicalizePaint {
michael@0 992 public:
michael@0 993 SkCanonicalizePaint(const SkPaint& paint) : fPaint(&paint), fScale(0) {
michael@0 994 if (paint.isLinearText() || paint.tooBigToUseCache()) {
michael@0 995 SkPaint* p = fLazy.set(paint);
michael@0 996 fScale = p->setupForAsPaths();
michael@0 997 fPaint = p;
michael@0 998 }
michael@0 999 }
michael@0 1000
michael@0 1001 const SkPaint& getPaint() const { return *fPaint; }
michael@0 1002
michael@0 1003 /**
michael@0 1004 * Returns 0 if the paint was unmodified, or the scale factor need to
michael@0 1005 * the original textSize
michael@0 1006 */
michael@0 1007 SkScalar getScale() const { return fScale; }
michael@0 1008
michael@0 1009 private:
michael@0 1010 const SkPaint* fPaint;
michael@0 1011 SkScalar fScale;
michael@0 1012 SkTLazy<SkPaint> fLazy;
michael@0 1013 };
michael@0 1014
michael@0 1015 static void set_bounds(const SkGlyph& g, SkRect* bounds) {
michael@0 1016 bounds->set(SkIntToScalar(g.fLeft),
michael@0 1017 SkIntToScalar(g.fTop),
michael@0 1018 SkIntToScalar(g.fLeft + g.fWidth),
michael@0 1019 SkIntToScalar(g.fTop + g.fHeight));
michael@0 1020 }
michael@0 1021
michael@0 1022 // 64bits wide, with a 16bit bias. Useful when accumulating lots of 16.16 so
michael@0 1023 // we don't overflow along the way
michael@0 1024 typedef int64_t Sk48Dot16;
michael@0 1025
michael@0 1026 static inline float Sk48Dot16ToScalar(Sk48Dot16 x) {
michael@0 1027 return (float) (x * 1.5258789e-5); // x * (1 / 65536.0f)
michael@0 1028 }
michael@0 1029
michael@0 1030 static void join_bounds_x(const SkGlyph& g, SkRect* bounds, Sk48Dot16 dx) {
michael@0 1031 SkScalar sx = Sk48Dot16ToScalar(dx);
michael@0 1032 bounds->join(SkIntToScalar(g.fLeft) + sx,
michael@0 1033 SkIntToScalar(g.fTop),
michael@0 1034 SkIntToScalar(g.fLeft + g.fWidth) + sx,
michael@0 1035 SkIntToScalar(g.fTop + g.fHeight));
michael@0 1036 }
michael@0 1037
michael@0 1038 static void join_bounds_y(const SkGlyph& g, SkRect* bounds, Sk48Dot16 dy) {
michael@0 1039 SkScalar sy = Sk48Dot16ToScalar(dy);
michael@0 1040 bounds->join(SkIntToScalar(g.fLeft),
michael@0 1041 SkIntToScalar(g.fTop) + sy,
michael@0 1042 SkIntToScalar(g.fLeft + g.fWidth),
michael@0 1043 SkIntToScalar(g.fTop + g.fHeight) + sy);
michael@0 1044 }
michael@0 1045
michael@0 1046 typedef void (*JoinBoundsProc)(const SkGlyph&, SkRect*, Sk48Dot16);
michael@0 1047
michael@0 1048 // xyIndex is 0 for fAdvanceX or 1 for fAdvanceY
michael@0 1049 static SkFixed advance(const SkGlyph& glyph, int xyIndex) {
michael@0 1050 SkASSERT(0 == xyIndex || 1 == xyIndex);
michael@0 1051 return (&glyph.fAdvanceX)[xyIndex];
michael@0 1052 }
michael@0 1053
michael@0 1054 SkScalar SkPaint::measure_text(SkGlyphCache* cache,
michael@0 1055 const char* text, size_t byteLength,
michael@0 1056 int* count, SkRect* bounds) const {
michael@0 1057 SkASSERT(count);
michael@0 1058 if (byteLength == 0) {
michael@0 1059 *count = 0;
michael@0 1060 if (bounds) {
michael@0 1061 bounds->setEmpty();
michael@0 1062 }
michael@0 1063 return 0;
michael@0 1064 }
michael@0 1065
michael@0 1066 SkMeasureCacheProc glyphCacheProc;
michael@0 1067 glyphCacheProc = this->getMeasureCacheProc(kForward_TextBufferDirection,
michael@0 1068 NULL != bounds);
michael@0 1069
michael@0 1070 int xyIndex;
michael@0 1071 JoinBoundsProc joinBoundsProc;
michael@0 1072 if (this->isVerticalText()) {
michael@0 1073 xyIndex = 1;
michael@0 1074 joinBoundsProc = join_bounds_y;
michael@0 1075 } else {
michael@0 1076 xyIndex = 0;
michael@0 1077 joinBoundsProc = join_bounds_x;
michael@0 1078 }
michael@0 1079
michael@0 1080 int n = 1;
michael@0 1081 const char* stop = (const char*)text + byteLength;
michael@0 1082 const SkGlyph* g = &glyphCacheProc(cache, &text);
michael@0 1083 // our accumulated fixed-point advances might overflow 16.16, so we use
michael@0 1084 // a 48.16 (64bit) accumulator, and then convert that to scalar at the
michael@0 1085 // very end.
michael@0 1086 Sk48Dot16 x = advance(*g, xyIndex);
michael@0 1087
michael@0 1088 SkAutoKern autokern;
michael@0 1089
michael@0 1090 if (NULL == bounds) {
michael@0 1091 if (this->isDevKernText()) {
michael@0 1092 int rsb;
michael@0 1093 for (; text < stop; n++) {
michael@0 1094 rsb = g->fRsbDelta;
michael@0 1095 g = &glyphCacheProc(cache, &text);
michael@0 1096 x += SkAutoKern_AdjustF(rsb, g->fLsbDelta) + advance(*g, xyIndex);
michael@0 1097 }
michael@0 1098 } else {
michael@0 1099 for (; text < stop; n++) {
michael@0 1100 x += advance(glyphCacheProc(cache, &text), xyIndex);
michael@0 1101 }
michael@0 1102 }
michael@0 1103 } else {
michael@0 1104 set_bounds(*g, bounds);
michael@0 1105 if (this->isDevKernText()) {
michael@0 1106 int rsb;
michael@0 1107 for (; text < stop; n++) {
michael@0 1108 rsb = g->fRsbDelta;
michael@0 1109 g = &glyphCacheProc(cache, &text);
michael@0 1110 x += SkAutoKern_AdjustF(rsb, g->fLsbDelta);
michael@0 1111 joinBoundsProc(*g, bounds, x);
michael@0 1112 x += advance(*g, xyIndex);
michael@0 1113 }
michael@0 1114 } else {
michael@0 1115 for (; text < stop; n++) {
michael@0 1116 g = &glyphCacheProc(cache, &text);
michael@0 1117 joinBoundsProc(*g, bounds, x);
michael@0 1118 x += advance(*g, xyIndex);
michael@0 1119 }
michael@0 1120 }
michael@0 1121 }
michael@0 1122 SkASSERT(text == stop);
michael@0 1123
michael@0 1124 *count = n;
michael@0 1125 return Sk48Dot16ToScalar(x);
michael@0 1126 }
michael@0 1127
michael@0 1128 SkScalar SkPaint::measureText(const void* textData, size_t length,
michael@0 1129 SkRect* bounds, SkScalar zoom) const {
michael@0 1130 const char* text = (const char*)textData;
michael@0 1131 SkASSERT(text != NULL || length == 0);
michael@0 1132
michael@0 1133 SkCanonicalizePaint canon(*this);
michael@0 1134 const SkPaint& paint = canon.getPaint();
michael@0 1135 SkScalar scale = canon.getScale();
michael@0 1136
michael@0 1137 SkMatrix zoomMatrix, *zoomPtr = NULL;
michael@0 1138 if (zoom) {
michael@0 1139 zoomMatrix.setScale(zoom, zoom);
michael@0 1140 zoomPtr = &zoomMatrix;
michael@0 1141 }
michael@0 1142
michael@0 1143 SkAutoGlyphCache autoCache(paint, NULL, zoomPtr);
michael@0 1144 SkGlyphCache* cache = autoCache.getCache();
michael@0 1145
michael@0 1146 SkScalar width = 0;
michael@0 1147
michael@0 1148 if (length > 0) {
michael@0 1149 int tempCount;
michael@0 1150
michael@0 1151 width = paint.measure_text(cache, text, length, &tempCount, bounds);
michael@0 1152 if (scale) {
michael@0 1153 width = SkScalarMul(width, scale);
michael@0 1154 if (bounds) {
michael@0 1155 bounds->fLeft = SkScalarMul(bounds->fLeft, scale);
michael@0 1156 bounds->fTop = SkScalarMul(bounds->fTop, scale);
michael@0 1157 bounds->fRight = SkScalarMul(bounds->fRight, scale);
michael@0 1158 bounds->fBottom = SkScalarMul(bounds->fBottom, scale);
michael@0 1159 }
michael@0 1160 }
michael@0 1161 } else if (bounds) {
michael@0 1162 // ensure that even if we don't measure_text we still update the bounds
michael@0 1163 bounds->setEmpty();
michael@0 1164 }
michael@0 1165 return width;
michael@0 1166 }
michael@0 1167
michael@0 1168 typedef bool (*SkTextBufferPred)(const char* text, const char* stop);
michael@0 1169
michael@0 1170 static bool forward_textBufferPred(const char* text, const char* stop) {
michael@0 1171 return text < stop;
michael@0 1172 }
michael@0 1173
michael@0 1174 static bool backward_textBufferPred(const char* text, const char* stop) {
michael@0 1175 return text > stop;
michael@0 1176 }
michael@0 1177
michael@0 1178 static SkTextBufferPred chooseTextBufferPred(SkPaint::TextBufferDirection tbd,
michael@0 1179 const char** text, size_t length,
michael@0 1180 const char** stop) {
michael@0 1181 if (SkPaint::kForward_TextBufferDirection == tbd) {
michael@0 1182 *stop = *text + length;
michael@0 1183 return forward_textBufferPred;
michael@0 1184 } else {
michael@0 1185 // text should point to the end of the buffer, and stop to the beginning
michael@0 1186 *stop = *text;
michael@0 1187 *text += length;
michael@0 1188 return backward_textBufferPred;
michael@0 1189 }
michael@0 1190 }
michael@0 1191
michael@0 1192 size_t SkPaint::breakText(const void* textD, size_t length, SkScalar maxWidth,
michael@0 1193 SkScalar* measuredWidth,
michael@0 1194 TextBufferDirection tbd) const {
michael@0 1195 if (0 == length || 0 >= maxWidth) {
michael@0 1196 if (measuredWidth) {
michael@0 1197 *measuredWidth = 0;
michael@0 1198 }
michael@0 1199 return 0;
michael@0 1200 }
michael@0 1201
michael@0 1202 if (0 == fTextSize) {
michael@0 1203 if (measuredWidth) {
michael@0 1204 *measuredWidth = 0;
michael@0 1205 }
michael@0 1206 return length;
michael@0 1207 }
michael@0 1208
michael@0 1209 SkASSERT(textD != NULL);
michael@0 1210 const char* text = (const char*)textD;
michael@0 1211
michael@0 1212 SkCanonicalizePaint canon(*this);
michael@0 1213 const SkPaint& paint = canon.getPaint();
michael@0 1214 SkScalar scale = canon.getScale();
michael@0 1215
michael@0 1216 // adjust max in case we changed the textSize in paint
michael@0 1217 if (scale) {
michael@0 1218 maxWidth /= scale;
michael@0 1219 }
michael@0 1220
michael@0 1221 SkAutoGlyphCache autoCache(paint, NULL, NULL);
michael@0 1222 SkGlyphCache* cache = autoCache.getCache();
michael@0 1223
michael@0 1224 SkMeasureCacheProc glyphCacheProc = paint.getMeasureCacheProc(tbd, false);
michael@0 1225 const char* stop;
michael@0 1226 SkTextBufferPred pred = chooseTextBufferPred(tbd, &text, length, &stop);
michael@0 1227 const int xyIndex = paint.isVerticalText() ? 1 : 0;
michael@0 1228 // use 64bits for our accumulator, to avoid overflowing 16.16
michael@0 1229 Sk48Dot16 max = SkScalarToFixed(maxWidth);
michael@0 1230 Sk48Dot16 width = 0;
michael@0 1231
michael@0 1232 SkAutoKern autokern;
michael@0 1233
michael@0 1234 if (this->isDevKernText()) {
michael@0 1235 int rsb = 0;
michael@0 1236 while (pred(text, stop)) {
michael@0 1237 const char* curr = text;
michael@0 1238 const SkGlyph& g = glyphCacheProc(cache, &text);
michael@0 1239 SkFixed x = SkAutoKern_AdjustF(rsb, g.fLsbDelta) + advance(g, xyIndex);
michael@0 1240 if ((width += x) > max) {
michael@0 1241 width -= x;
michael@0 1242 text = curr;
michael@0 1243 break;
michael@0 1244 }
michael@0 1245 rsb = g.fRsbDelta;
michael@0 1246 }
michael@0 1247 } else {
michael@0 1248 while (pred(text, stop)) {
michael@0 1249 const char* curr = text;
michael@0 1250 SkFixed x = advance(glyphCacheProc(cache, &text), xyIndex);
michael@0 1251 if ((width += x) > max) {
michael@0 1252 width -= x;
michael@0 1253 text = curr;
michael@0 1254 break;
michael@0 1255 }
michael@0 1256 }
michael@0 1257 }
michael@0 1258
michael@0 1259 if (measuredWidth) {
michael@0 1260 SkScalar scalarWidth = Sk48Dot16ToScalar(width);
michael@0 1261 if (scale) {
michael@0 1262 scalarWidth = SkScalarMul(scalarWidth, scale);
michael@0 1263 }
michael@0 1264 *measuredWidth = scalarWidth;
michael@0 1265 }
michael@0 1266
michael@0 1267 // return the number of bytes measured
michael@0 1268 return (kForward_TextBufferDirection == tbd) ?
michael@0 1269 text - stop + length : stop - text + length;
michael@0 1270 }
michael@0 1271
michael@0 1272 ///////////////////////////////////////////////////////////////////////////////
michael@0 1273
michael@0 1274 static bool FontMetricsCacheProc(const SkGlyphCache* cache, void* context) {
michael@0 1275 *(SkPaint::FontMetrics*)context = cache->getFontMetrics();
michael@0 1276 return false; // don't detach the cache
michael@0 1277 }
michael@0 1278
michael@0 1279 static void FontMetricsDescProc(SkTypeface* typeface, const SkDescriptor* desc,
michael@0 1280 void* context) {
michael@0 1281 SkGlyphCache::VisitCache(typeface, desc, FontMetricsCacheProc, context);
michael@0 1282 }
michael@0 1283
michael@0 1284 SkScalar SkPaint::getFontMetrics(FontMetrics* metrics, SkScalar zoom) const {
michael@0 1285 SkCanonicalizePaint canon(*this);
michael@0 1286 const SkPaint& paint = canon.getPaint();
michael@0 1287 SkScalar scale = canon.getScale();
michael@0 1288
michael@0 1289 SkMatrix zoomMatrix, *zoomPtr = NULL;
michael@0 1290 if (zoom) {
michael@0 1291 zoomMatrix.setScale(zoom, zoom);
michael@0 1292 zoomPtr = &zoomMatrix;
michael@0 1293 }
michael@0 1294
michael@0 1295 FontMetrics storage;
michael@0 1296 if (NULL == metrics) {
michael@0 1297 metrics = &storage;
michael@0 1298 }
michael@0 1299
michael@0 1300 paint.descriptorProc(NULL, zoomPtr, FontMetricsDescProc, metrics, true);
michael@0 1301
michael@0 1302 if (scale) {
michael@0 1303 metrics->fTop = SkScalarMul(metrics->fTop, scale);
michael@0 1304 metrics->fAscent = SkScalarMul(metrics->fAscent, scale);
michael@0 1305 metrics->fDescent = SkScalarMul(metrics->fDescent, scale);
michael@0 1306 metrics->fBottom = SkScalarMul(metrics->fBottom, scale);
michael@0 1307 metrics->fLeading = SkScalarMul(metrics->fLeading, scale);
michael@0 1308 metrics->fAvgCharWidth = SkScalarMul(metrics->fAvgCharWidth, scale);
michael@0 1309 metrics->fXMin = SkScalarMul(metrics->fXMin, scale);
michael@0 1310 metrics->fXMax = SkScalarMul(metrics->fXMax, scale);
michael@0 1311 metrics->fXHeight = SkScalarMul(metrics->fXHeight, scale);
michael@0 1312 metrics->fUnderlineThickness = SkScalarMul(metrics->fUnderlineThickness, scale);
michael@0 1313 metrics->fUnderlinePosition = SkScalarMul(metrics->fUnderlinePosition, scale);
michael@0 1314 }
michael@0 1315 return metrics->fDescent - metrics->fAscent + metrics->fLeading;
michael@0 1316 }
michael@0 1317
michael@0 1318 ///////////////////////////////////////////////////////////////////////////////
michael@0 1319
michael@0 1320 static void set_bounds(const SkGlyph& g, SkRect* bounds, SkScalar scale) {
michael@0 1321 bounds->set(g.fLeft * scale,
michael@0 1322 g.fTop * scale,
michael@0 1323 (g.fLeft + g.fWidth) * scale,
michael@0 1324 (g.fTop + g.fHeight) * scale);
michael@0 1325 }
michael@0 1326
michael@0 1327 int SkPaint::getTextWidths(const void* textData, size_t byteLength,
michael@0 1328 SkScalar widths[], SkRect bounds[]) const {
michael@0 1329 if (0 == byteLength) {
michael@0 1330 return 0;
michael@0 1331 }
michael@0 1332
michael@0 1333 SkASSERT(NULL != textData);
michael@0 1334
michael@0 1335 if (NULL == widths && NULL == bounds) {
michael@0 1336 return this->countText(textData, byteLength);
michael@0 1337 }
michael@0 1338
michael@0 1339 SkCanonicalizePaint canon(*this);
michael@0 1340 const SkPaint& paint = canon.getPaint();
michael@0 1341 SkScalar scale = canon.getScale();
michael@0 1342
michael@0 1343 SkAutoGlyphCache autoCache(paint, NULL, NULL);
michael@0 1344 SkGlyphCache* cache = autoCache.getCache();
michael@0 1345 SkMeasureCacheProc glyphCacheProc;
michael@0 1346 glyphCacheProc = paint.getMeasureCacheProc(kForward_TextBufferDirection,
michael@0 1347 NULL != bounds);
michael@0 1348
michael@0 1349 const char* text = (const char*)textData;
michael@0 1350 const char* stop = text + byteLength;
michael@0 1351 int count = 0;
michael@0 1352 const int xyIndex = paint.isVerticalText() ? 1 : 0;
michael@0 1353
michael@0 1354 if (this->isDevKernText()) {
michael@0 1355 // we adjust the widths returned here through auto-kerning
michael@0 1356 SkAutoKern autokern;
michael@0 1357 SkFixed prevWidth = 0;
michael@0 1358
michael@0 1359 if (scale) {
michael@0 1360 while (text < stop) {
michael@0 1361 const SkGlyph& g = glyphCacheProc(cache, &text);
michael@0 1362 if (widths) {
michael@0 1363 SkFixed adjust = autokern.adjust(g);
michael@0 1364
michael@0 1365 if (count > 0) {
michael@0 1366 SkScalar w = SkFixedToScalar(prevWidth + adjust);
michael@0 1367 *widths++ = SkScalarMul(w, scale);
michael@0 1368 }
michael@0 1369 prevWidth = advance(g, xyIndex);
michael@0 1370 }
michael@0 1371 if (bounds) {
michael@0 1372 set_bounds(g, bounds++, scale);
michael@0 1373 }
michael@0 1374 ++count;
michael@0 1375 }
michael@0 1376 if (count > 0 && widths) {
michael@0 1377 *widths = SkScalarMul(SkFixedToScalar(prevWidth), scale);
michael@0 1378 }
michael@0 1379 } else {
michael@0 1380 while (text < stop) {
michael@0 1381 const SkGlyph& g = glyphCacheProc(cache, &text);
michael@0 1382 if (widths) {
michael@0 1383 SkFixed adjust = autokern.adjust(g);
michael@0 1384
michael@0 1385 if (count > 0) {
michael@0 1386 *widths++ = SkFixedToScalar(prevWidth + adjust);
michael@0 1387 }
michael@0 1388 prevWidth = advance(g, xyIndex);
michael@0 1389 }
michael@0 1390 if (bounds) {
michael@0 1391 set_bounds(g, bounds++);
michael@0 1392 }
michael@0 1393 ++count;
michael@0 1394 }
michael@0 1395 if (count > 0 && widths) {
michael@0 1396 *widths = SkFixedToScalar(prevWidth);
michael@0 1397 }
michael@0 1398 }
michael@0 1399 } else { // no devkern
michael@0 1400 if (scale) {
michael@0 1401 while (text < stop) {
michael@0 1402 const SkGlyph& g = glyphCacheProc(cache, &text);
michael@0 1403 if (widths) {
michael@0 1404 *widths++ = SkScalarMul(SkFixedToScalar(advance(g, xyIndex)),
michael@0 1405 scale);
michael@0 1406 }
michael@0 1407 if (bounds) {
michael@0 1408 set_bounds(g, bounds++, scale);
michael@0 1409 }
michael@0 1410 ++count;
michael@0 1411 }
michael@0 1412 } else {
michael@0 1413 while (text < stop) {
michael@0 1414 const SkGlyph& g = glyphCacheProc(cache, &text);
michael@0 1415 if (widths) {
michael@0 1416 *widths++ = SkFixedToScalar(advance(g, xyIndex));
michael@0 1417 }
michael@0 1418 if (bounds) {
michael@0 1419 set_bounds(g, bounds++);
michael@0 1420 }
michael@0 1421 ++count;
michael@0 1422 }
michael@0 1423 }
michael@0 1424 }
michael@0 1425
michael@0 1426 SkASSERT(text == stop);
michael@0 1427 return count;
michael@0 1428 }
michael@0 1429
michael@0 1430 ///////////////////////////////////////////////////////////////////////////////
michael@0 1431
michael@0 1432 #include "SkDraw.h"
michael@0 1433
michael@0 1434 void SkPaint::getTextPath(const void* textData, size_t length,
michael@0 1435 SkScalar x, SkScalar y, SkPath* path) const {
michael@0 1436 SkASSERT(length == 0 || textData != NULL);
michael@0 1437
michael@0 1438 const char* text = (const char*)textData;
michael@0 1439 if (text == NULL || length == 0 || path == NULL) {
michael@0 1440 return;
michael@0 1441 }
michael@0 1442
michael@0 1443 SkTextToPathIter iter(text, length, *this, false);
michael@0 1444 SkMatrix matrix;
michael@0 1445 SkScalar prevXPos = 0;
michael@0 1446
michael@0 1447 matrix.setScale(iter.getPathScale(), iter.getPathScale());
michael@0 1448 matrix.postTranslate(x, y);
michael@0 1449 path->reset();
michael@0 1450
michael@0 1451 SkScalar xpos;
michael@0 1452 const SkPath* iterPath;
michael@0 1453 while (iter.next(&iterPath, &xpos)) {
michael@0 1454 matrix.postTranslate(xpos - prevXPos, 0);
michael@0 1455 if (iterPath) {
michael@0 1456 path->addPath(*iterPath, matrix);
michael@0 1457 }
michael@0 1458 prevXPos = xpos;
michael@0 1459 }
michael@0 1460 }
michael@0 1461
michael@0 1462 void SkPaint::getPosTextPath(const void* textData, size_t length,
michael@0 1463 const SkPoint pos[], SkPath* path) const {
michael@0 1464 SkASSERT(length == 0 || textData != NULL);
michael@0 1465
michael@0 1466 const char* text = (const char*)textData;
michael@0 1467 if (text == NULL || length == 0 || path == NULL) {
michael@0 1468 return;
michael@0 1469 }
michael@0 1470
michael@0 1471 SkTextToPathIter iter(text, length, *this, false);
michael@0 1472 SkMatrix matrix;
michael@0 1473 SkPoint prevPos;
michael@0 1474 prevPos.set(0, 0);
michael@0 1475
michael@0 1476 matrix.setScale(iter.getPathScale(), iter.getPathScale());
michael@0 1477 path->reset();
michael@0 1478
michael@0 1479 unsigned int i = 0;
michael@0 1480 const SkPath* iterPath;
michael@0 1481 while (iter.next(&iterPath, NULL)) {
michael@0 1482 matrix.postTranslate(pos[i].fX - prevPos.fX, pos[i].fY - prevPos.fY);
michael@0 1483 if (iterPath) {
michael@0 1484 path->addPath(*iterPath, matrix);
michael@0 1485 }
michael@0 1486 prevPos = pos[i];
michael@0 1487 i++;
michael@0 1488 }
michael@0 1489 }
michael@0 1490
michael@0 1491 static void add_flattenable(SkDescriptor* desc, uint32_t tag,
michael@0 1492 SkWriteBuffer* buffer) {
michael@0 1493 buffer->writeToMemory(desc->addEntry(tag, buffer->bytesWritten(), NULL));
michael@0 1494 }
michael@0 1495
michael@0 1496 // SkFontHost can override this choice in FilterRec()
michael@0 1497 static SkMask::Format computeMaskFormat(const SkPaint& paint) {
michael@0 1498 uint32_t flags = paint.getFlags();
michael@0 1499
michael@0 1500 // Antialiasing being disabled trumps all other settings.
michael@0 1501 if (!(flags & SkPaint::kAntiAlias_Flag)) {
michael@0 1502 return SkMask::kBW_Format;
michael@0 1503 }
michael@0 1504
michael@0 1505 if (flags & SkPaint::kLCDRenderText_Flag) {
michael@0 1506 return SkMask::kLCD16_Format;
michael@0 1507 }
michael@0 1508
michael@0 1509 return SkMask::kA8_Format;
michael@0 1510 }
michael@0 1511
michael@0 1512 // if linear-text is on, then we force hinting to be off (since that's sort of
michael@0 1513 // the point of linear-text.
michael@0 1514 static SkPaint::Hinting computeHinting(const SkPaint& paint) {
michael@0 1515 SkPaint::Hinting h = paint.getHinting();
michael@0 1516 if (paint.isLinearText()) {
michael@0 1517 h = SkPaint::kNo_Hinting;
michael@0 1518 }
michael@0 1519 return h;
michael@0 1520 }
michael@0 1521
michael@0 1522 // return true if the paint is just a single color (i.e. not a shader). If its
michael@0 1523 // a shader, then we can't compute a const luminance for it :(
michael@0 1524 static bool justAColor(const SkPaint& paint, SkColor* color) {
michael@0 1525 if (paint.getShader()) {
michael@0 1526 return false;
michael@0 1527 }
michael@0 1528 SkColor c = paint.getColor();
michael@0 1529 if (paint.getColorFilter()) {
michael@0 1530 c = paint.getColorFilter()->filterColor(c);
michael@0 1531 }
michael@0 1532 if (color) {
michael@0 1533 *color = c;
michael@0 1534 }
michael@0 1535 return true;
michael@0 1536 }
michael@0 1537
michael@0 1538 static SkColor computeLuminanceColor(const SkPaint& paint) {
michael@0 1539 SkColor c;
michael@0 1540 if (!justAColor(paint, &c)) {
michael@0 1541 c = SkColorSetRGB(0x7F, 0x80, 0x7F);
michael@0 1542 }
michael@0 1543 return c;
michael@0 1544 }
michael@0 1545
michael@0 1546 #define assert_byte(x) SkASSERT(0 == ((x) >> 8))
michael@0 1547
michael@0 1548 // Beyond this size, LCD doesn't appreciably improve quality, but it always
michael@0 1549 // cost more RAM and draws slower, so we set a cap.
michael@0 1550 #ifndef SK_MAX_SIZE_FOR_LCDTEXT
michael@0 1551 #define SK_MAX_SIZE_FOR_LCDTEXT 48
michael@0 1552 #endif
michael@0 1553
michael@0 1554 static bool tooBigForLCD(const SkScalerContext::Rec& rec) {
michael@0 1555 SkScalar area = rec.fPost2x2[0][0] * rec.fPost2x2[1][1] -
michael@0 1556 rec.fPost2x2[1][0] * rec.fPost2x2[0][1];
michael@0 1557 SkScalar size = SkScalarSqrt(SkScalarAbs(area)) * rec.fTextSize;
michael@0 1558 return size > SkIntToScalar(SK_MAX_SIZE_FOR_LCDTEXT);
michael@0 1559 }
michael@0 1560
michael@0 1561 /*
michael@0 1562 * Return the scalar with only limited fractional precision. Used to consolidate matrices
michael@0 1563 * that vary only slightly when we create our key into the font cache, since the font scaler
michael@0 1564 * typically returns the same looking resuts for tiny changes in the matrix.
michael@0 1565 */
michael@0 1566 static SkScalar sk_relax(SkScalar x) {
michael@0 1567 int n = sk_float_round2int(x * 1024);
michael@0 1568 return n / 1024.0f;
michael@0 1569 }
michael@0 1570
michael@0 1571 void SkScalerContext::MakeRec(const SkPaint& paint,
michael@0 1572 const SkDeviceProperties* deviceProperties,
michael@0 1573 const SkMatrix* deviceMatrix,
michael@0 1574 Rec* rec) {
michael@0 1575 SkASSERT(deviceMatrix == NULL || !deviceMatrix->hasPerspective());
michael@0 1576
michael@0 1577 SkTypeface* typeface = paint.getTypeface();
michael@0 1578 if (NULL == typeface) {
michael@0 1579 typeface = SkTypeface::GetDefaultTypeface();
michael@0 1580 }
michael@0 1581 rec->fOrigFontID = typeface->uniqueID();
michael@0 1582 rec->fFontID = rec->fOrigFontID;
michael@0 1583 rec->fTextSize = paint.getTextSize();
michael@0 1584 rec->fPreScaleX = paint.getTextScaleX();
michael@0 1585 rec->fPreSkewX = paint.getTextSkewX();
michael@0 1586
michael@0 1587 if (deviceMatrix) {
michael@0 1588 rec->fPost2x2[0][0] = sk_relax(deviceMatrix->getScaleX());
michael@0 1589 rec->fPost2x2[0][1] = sk_relax(deviceMatrix->getSkewX());
michael@0 1590 rec->fPost2x2[1][0] = sk_relax(deviceMatrix->getSkewY());
michael@0 1591 rec->fPost2x2[1][1] = sk_relax(deviceMatrix->getScaleY());
michael@0 1592 } else {
michael@0 1593 rec->fPost2x2[0][0] = rec->fPost2x2[1][1] = SK_Scalar1;
michael@0 1594 rec->fPost2x2[0][1] = rec->fPost2x2[1][0] = 0;
michael@0 1595 }
michael@0 1596
michael@0 1597 SkPaint::Style style = paint.getStyle();
michael@0 1598 SkScalar strokeWidth = paint.getStrokeWidth();
michael@0 1599
michael@0 1600 unsigned flags = 0;
michael@0 1601
michael@0 1602 if (paint.isFakeBoldText()) {
michael@0 1603 #ifdef SK_USE_FREETYPE_EMBOLDEN
michael@0 1604 flags |= SkScalerContext::kEmbolden_Flag;
michael@0 1605 #else
michael@0 1606 SkScalar fakeBoldScale = SkScalarInterpFunc(paint.getTextSize(),
michael@0 1607 kStdFakeBoldInterpKeys,
michael@0 1608 kStdFakeBoldInterpValues,
michael@0 1609 kStdFakeBoldInterpLength);
michael@0 1610 SkScalar extra = SkScalarMul(paint.getTextSize(), fakeBoldScale);
michael@0 1611
michael@0 1612 if (style == SkPaint::kFill_Style) {
michael@0 1613 style = SkPaint::kStrokeAndFill_Style;
michael@0 1614 strokeWidth = extra; // ignore paint's strokeWidth if it was "fill"
michael@0 1615 } else {
michael@0 1616 strokeWidth += extra;
michael@0 1617 }
michael@0 1618 #endif
michael@0 1619 }
michael@0 1620
michael@0 1621 if (paint.isDevKernText()) {
michael@0 1622 flags |= SkScalerContext::kDevKernText_Flag;
michael@0 1623 }
michael@0 1624
michael@0 1625 if (style != SkPaint::kFill_Style && strokeWidth > 0) {
michael@0 1626 rec->fFrameWidth = strokeWidth;
michael@0 1627 rec->fMiterLimit = paint.getStrokeMiter();
michael@0 1628 rec->fStrokeJoin = SkToU8(paint.getStrokeJoin());
michael@0 1629
michael@0 1630 if (style == SkPaint::kStrokeAndFill_Style) {
michael@0 1631 flags |= SkScalerContext::kFrameAndFill_Flag;
michael@0 1632 }
michael@0 1633 } else {
michael@0 1634 rec->fFrameWidth = 0;
michael@0 1635 rec->fMiterLimit = 0;
michael@0 1636 rec->fStrokeJoin = 0;
michael@0 1637 }
michael@0 1638
michael@0 1639 rec->fMaskFormat = SkToU8(computeMaskFormat(paint));
michael@0 1640
michael@0 1641 SkDeviceProperties::Geometry geometry = deviceProperties
michael@0 1642 ? deviceProperties->fGeometry
michael@0 1643 : SkDeviceProperties::Geometry::MakeDefault();
michael@0 1644 if (SkMask::kLCD16_Format == rec->fMaskFormat || SkMask::kLCD32_Format == rec->fMaskFormat) {
michael@0 1645 if (!geometry.isOrientationKnown() || !geometry.isLayoutKnown() || tooBigForLCD(*rec)) {
michael@0 1646 // eeek, can't support LCD
michael@0 1647 rec->fMaskFormat = SkMask::kA8_Format;
michael@0 1648 } else {
michael@0 1649 if (SkDeviceProperties::Geometry::kVertical_Orientation == geometry.getOrientation()) {
michael@0 1650 flags |= SkScalerContext::kLCD_Vertical_Flag;
michael@0 1651 }
michael@0 1652 if (SkDeviceProperties::Geometry::kBGR_Layout == geometry.getLayout()) {
michael@0 1653 flags |= SkScalerContext::kLCD_BGROrder_Flag;
michael@0 1654 }
michael@0 1655 }
michael@0 1656 }
michael@0 1657
michael@0 1658 if (paint.isEmbeddedBitmapText()) {
michael@0 1659 flags |= SkScalerContext::kEmbeddedBitmapText_Flag;
michael@0 1660 }
michael@0 1661 if (paint.isSubpixelText()) {
michael@0 1662 flags |= SkScalerContext::kSubpixelPositioning_Flag;
michael@0 1663 }
michael@0 1664 if (paint.isAutohinted()) {
michael@0 1665 flags |= SkScalerContext::kForceAutohinting_Flag;
michael@0 1666 }
michael@0 1667 if (paint.isVerticalText()) {
michael@0 1668 flags |= SkScalerContext::kVertical_Flag;
michael@0 1669 }
michael@0 1670 if (paint.getFlags() & SkPaint::kGenA8FromLCD_Flag) {
michael@0 1671 flags |= SkScalerContext::kGenA8FromLCD_Flag;
michael@0 1672 }
michael@0 1673 rec->fFlags = SkToU16(flags);
michael@0 1674
michael@0 1675 // these modify fFlags, so do them after assigning fFlags
michael@0 1676 rec->setHinting(computeHinting(paint));
michael@0 1677
michael@0 1678 rec->setLuminanceColor(computeLuminanceColor(paint));
michael@0 1679
michael@0 1680 if (NULL == deviceProperties) {
michael@0 1681 rec->setDeviceGamma(SK_GAMMA_EXPONENT);
michael@0 1682 rec->setPaintGamma(SK_GAMMA_EXPONENT);
michael@0 1683 } else {
michael@0 1684 rec->setDeviceGamma(deviceProperties->fGamma);
michael@0 1685
michael@0 1686 //For now always set the paint gamma equal to the device gamma.
michael@0 1687 //The math in SkMaskGamma can handle them being different,
michael@0 1688 //but it requires superluminous masks when
michael@0 1689 //Ex : deviceGamma(x) < paintGamma(x) and x is sufficiently large.
michael@0 1690 rec->setPaintGamma(deviceProperties->fGamma);
michael@0 1691 }
michael@0 1692
michael@0 1693 #ifdef SK_GAMMA_CONTRAST
michael@0 1694 rec->setContrast(SK_GAMMA_CONTRAST);
michael@0 1695 #else
michael@0 1696 /**
michael@0 1697 * A value of 0.5 for SK_GAMMA_CONTRAST appears to be a good compromise.
michael@0 1698 * With lower values small text appears washed out (though correctly so).
michael@0 1699 * With higher values lcd fringing is worse and the smoothing effect of
michael@0 1700 * partial coverage is diminished.
michael@0 1701 */
michael@0 1702 rec->setContrast(0.5f);
michael@0 1703 #endif
michael@0 1704
michael@0 1705 rec->fReservedAlign = 0;
michael@0 1706
michael@0 1707 /* Allow the fonthost to modify our rec before we use it as a key into the
michael@0 1708 cache. This way if we're asking for something that they will ignore,
michael@0 1709 they can modify our rec up front, so we don't create duplicate cache
michael@0 1710 entries.
michael@0 1711 */
michael@0 1712 typeface->onFilterRec(rec);
michael@0 1713
michael@0 1714 // be sure to call PostMakeRec(rec) before you actually use it!
michael@0 1715 }
michael@0 1716
michael@0 1717 /**
michael@0 1718 * In order to call cachedDeviceLuminance, cachedPaintLuminance, or
michael@0 1719 * cachedMaskGamma the caller must hold the gMaskGammaCacheMutex and continue
michael@0 1720 * to hold it until the returned pointer is refed or forgotten.
michael@0 1721 */
michael@0 1722 SK_DECLARE_STATIC_MUTEX(gMaskGammaCacheMutex);
michael@0 1723
michael@0 1724 static SkMaskGamma* gLinearMaskGamma = NULL;
michael@0 1725 static SkMaskGamma* gMaskGamma = NULL;
michael@0 1726 static SkScalar gContrast = SK_ScalarMin;
michael@0 1727 static SkScalar gPaintGamma = SK_ScalarMin;
michael@0 1728 static SkScalar gDeviceGamma = SK_ScalarMin;
michael@0 1729 /**
michael@0 1730 * The caller must hold the gMaskGammaCacheMutex and continue to hold it until
michael@0 1731 * the returned SkMaskGamma pointer is refed or forgotten.
michael@0 1732 */
michael@0 1733 static const SkMaskGamma& cachedMaskGamma(SkScalar contrast, SkScalar paintGamma, SkScalar deviceGamma) {
michael@0 1734 if (0 == contrast && SK_Scalar1 == paintGamma && SK_Scalar1 == deviceGamma) {
michael@0 1735 if (NULL == gLinearMaskGamma) {
michael@0 1736 gLinearMaskGamma = SkNEW(SkMaskGamma);
michael@0 1737 }
michael@0 1738 return *gLinearMaskGamma;
michael@0 1739 }
michael@0 1740 if (gContrast != contrast || gPaintGamma != paintGamma || gDeviceGamma != deviceGamma) {
michael@0 1741 SkSafeUnref(gMaskGamma);
michael@0 1742 gMaskGamma = SkNEW_ARGS(SkMaskGamma, (contrast, paintGamma, deviceGamma));
michael@0 1743 gContrast = contrast;
michael@0 1744 gPaintGamma = paintGamma;
michael@0 1745 gDeviceGamma = deviceGamma;
michael@0 1746 }
michael@0 1747 return *gMaskGamma;
michael@0 1748 }
michael@0 1749
michael@0 1750 /*static*/ void SkPaint::Term() {
michael@0 1751 SkAutoMutexAcquire ama(gMaskGammaCacheMutex);
michael@0 1752
michael@0 1753 SkSafeUnref(gLinearMaskGamma);
michael@0 1754 gLinearMaskGamma = NULL;
michael@0 1755 SkSafeUnref(gMaskGamma);
michael@0 1756 gMaskGamma = NULL;
michael@0 1757 SkDEBUGCODE(gContrast = SK_ScalarMin;)
michael@0 1758 SkDEBUGCODE(gPaintGamma = SK_ScalarMin;)
michael@0 1759 SkDEBUGCODE(gDeviceGamma = SK_ScalarMin;)
michael@0 1760 }
michael@0 1761
michael@0 1762 /**
michael@0 1763 * We ensure that the rec is self-consistent and efficient (where possible)
michael@0 1764 */
michael@0 1765 void SkScalerContext::PostMakeRec(const SkPaint&, SkScalerContext::Rec* rec) {
michael@0 1766 /**
michael@0 1767 * If we're asking for A8, we force the colorlum to be gray, since that
michael@0 1768 * limits the number of unique entries, and the scaler will only look at
michael@0 1769 * the lum of one of them.
michael@0 1770 */
michael@0 1771 switch (rec->fMaskFormat) {
michael@0 1772 case SkMask::kLCD16_Format:
michael@0 1773 case SkMask::kLCD32_Format: {
michael@0 1774 // filter down the luminance color to a finite number of bits
michael@0 1775 SkColor color = rec->getLuminanceColor();
michael@0 1776 rec->setLuminanceColor(SkMaskGamma::CanonicalColor(color));
michael@0 1777 break;
michael@0 1778 }
michael@0 1779 case SkMask::kA8_Format: {
michael@0 1780 // filter down the luminance to a single component, since A8 can't
michael@0 1781 // use per-component information
michael@0 1782
michael@0 1783 SkColor color = rec->getLuminanceColor();
michael@0 1784 U8CPU lum = SkColorSpaceLuminance::computeLuminance(rec->getPaintGamma(), color);
michael@0 1785 //If we are asked to look like LCD, look like LCD.
michael@0 1786 if (!(rec->fFlags & SkScalerContext::kGenA8FromLCD_Flag)) {
michael@0 1787 // HACK: Prevents green from being pre-blended as white.
michael@0 1788 lum -= ((255 - lum) * lum) / 255;
michael@0 1789 }
michael@0 1790
michael@0 1791 // reduce to our finite number of bits
michael@0 1792 color = SkColorSetRGB(lum, lum, lum);
michael@0 1793 rec->setLuminanceColor(SkMaskGamma::CanonicalColor(color));
michael@0 1794 break;
michael@0 1795 }
michael@0 1796 case SkMask::kBW_Format:
michael@0 1797 // No need to differentiate gamma if we're BW
michael@0 1798 rec->ignorePreBlend();
michael@0 1799 break;
michael@0 1800 }
michael@0 1801 }
michael@0 1802
michael@0 1803 #define MIN_SIZE_FOR_EFFECT_BUFFER 1024
michael@0 1804
michael@0 1805 #ifdef SK_DEBUG
michael@0 1806 #define TEST_DESC
michael@0 1807 #endif
michael@0 1808
michael@0 1809 /*
michael@0 1810 * ignoreGamma tells us that the caller just wants metrics that are unaffected
michael@0 1811 * by gamma correction, so we jam the luminance field to 0 (most common value
michael@0 1812 * for black text) in hopes that we get a cache hit easier. A better solution
michael@0 1813 * would be for the fontcache lookup to know to ignore the luminance field
michael@0 1814 * entirely, but not sure how to do that and keep it fast.
michael@0 1815 */
michael@0 1816 void SkPaint::descriptorProc(const SkDeviceProperties* deviceProperties,
michael@0 1817 const SkMatrix* deviceMatrix,
michael@0 1818 void (*proc)(SkTypeface*, const SkDescriptor*, void*),
michael@0 1819 void* context, bool ignoreGamma) const {
michael@0 1820 SkScalerContext::Rec rec;
michael@0 1821
michael@0 1822 SkScalerContext::MakeRec(*this, deviceProperties, deviceMatrix, &rec);
michael@0 1823 if (ignoreGamma) {
michael@0 1824 rec.setLuminanceColor(0);
michael@0 1825 }
michael@0 1826
michael@0 1827 size_t descSize = sizeof(rec);
michael@0 1828 int entryCount = 1;
michael@0 1829 SkPathEffect* pe = this->getPathEffect();
michael@0 1830 SkMaskFilter* mf = this->getMaskFilter();
michael@0 1831 SkRasterizer* ra = this->getRasterizer();
michael@0 1832
michael@0 1833 SkWriteBuffer peBuffer, mfBuffer, raBuffer;
michael@0 1834
michael@0 1835 if (pe) {
michael@0 1836 peBuffer.writeFlattenable(pe);
michael@0 1837 descSize += peBuffer.bytesWritten();
michael@0 1838 entryCount += 1;
michael@0 1839 rec.fMaskFormat = SkMask::kA8_Format; // force antialiasing when we do the scan conversion
michael@0 1840 // seems like we could support kLCD as well at this point...
michael@0 1841 }
michael@0 1842 if (mf) {
michael@0 1843 mfBuffer.writeFlattenable(mf);
michael@0 1844 descSize += mfBuffer.bytesWritten();
michael@0 1845 entryCount += 1;
michael@0 1846 rec.fMaskFormat = SkMask::kA8_Format; // force antialiasing with maskfilters
michael@0 1847 /* Pre-blend is not currently applied to filtered text.
michael@0 1848 The primary filter is blur, for which contrast makes no sense,
michael@0 1849 and for which the destination guess error is more visible.
michael@0 1850 Also, all existing users of blur have calibrated for linear. */
michael@0 1851 rec.ignorePreBlend();
michael@0 1852 }
michael@0 1853 if (ra) {
michael@0 1854 raBuffer.writeFlattenable(ra);
michael@0 1855 descSize += raBuffer.bytesWritten();
michael@0 1856 entryCount += 1;
michael@0 1857 rec.fMaskFormat = SkMask::kA8_Format; // force antialiasing when we do the scan conversion
michael@0 1858 }
michael@0 1859
michael@0 1860 #ifdef SK_BUILD_FOR_ANDROID
michael@0 1861 SkWriteBuffer androidBuffer;
michael@0 1862 fPaintOptionsAndroid.flatten(androidBuffer);
michael@0 1863 descSize += androidBuffer.bytesWritten();
michael@0 1864 entryCount += 1;
michael@0 1865 #endif
michael@0 1866
michael@0 1867 ///////////////////////////////////////////////////////////////////////////
michael@0 1868 // Now that we're done tweaking the rec, call the PostMakeRec cleanup
michael@0 1869 SkScalerContext::PostMakeRec(*this, &rec);
michael@0 1870
michael@0 1871 descSize += SkDescriptor::ComputeOverhead(entryCount);
michael@0 1872
michael@0 1873 SkAutoDescriptor ad(descSize);
michael@0 1874 SkDescriptor* desc = ad.getDesc();
michael@0 1875
michael@0 1876 desc->init();
michael@0 1877 desc->addEntry(kRec_SkDescriptorTag, sizeof(rec), &rec);
michael@0 1878
michael@0 1879 #ifdef SK_BUILD_FOR_ANDROID
michael@0 1880 add_flattenable(desc, kAndroidOpts_SkDescriptorTag, &androidBuffer);
michael@0 1881 #endif
michael@0 1882
michael@0 1883 if (pe) {
michael@0 1884 add_flattenable(desc, kPathEffect_SkDescriptorTag, &peBuffer);
michael@0 1885 }
michael@0 1886 if (mf) {
michael@0 1887 add_flattenable(desc, kMaskFilter_SkDescriptorTag, &mfBuffer);
michael@0 1888 }
michael@0 1889 if (ra) {
michael@0 1890 add_flattenable(desc, kRasterizer_SkDescriptorTag, &raBuffer);
michael@0 1891 }
michael@0 1892
michael@0 1893 SkASSERT(descSize == desc->getLength());
michael@0 1894 desc->computeChecksum();
michael@0 1895
michael@0 1896 #ifdef TEST_DESC
michael@0 1897 {
michael@0 1898 // Check that we completely write the bytes in desc (our key), and that
michael@0 1899 // there are no uninitialized bytes. If there were, then we would get
michael@0 1900 // false-misses (or worse, false-hits) in our fontcache.
michael@0 1901 //
michael@0 1902 // We do this buy filling 2 others, one with 0s and the other with 1s
michael@0 1903 // and create those, and then check that all 3 are identical.
michael@0 1904 SkAutoDescriptor ad1(descSize);
michael@0 1905 SkAutoDescriptor ad2(descSize);
michael@0 1906 SkDescriptor* desc1 = ad1.getDesc();
michael@0 1907 SkDescriptor* desc2 = ad2.getDesc();
michael@0 1908
michael@0 1909 memset(desc1, 0x00, descSize);
michael@0 1910 memset(desc2, 0xFF, descSize);
michael@0 1911
michael@0 1912 desc1->init();
michael@0 1913 desc2->init();
michael@0 1914 desc1->addEntry(kRec_SkDescriptorTag, sizeof(rec), &rec);
michael@0 1915 desc2->addEntry(kRec_SkDescriptorTag, sizeof(rec), &rec);
michael@0 1916
michael@0 1917 #ifdef SK_BUILD_FOR_ANDROID
michael@0 1918 add_flattenable(desc1, kAndroidOpts_SkDescriptorTag, &androidBuffer);
michael@0 1919 add_flattenable(desc2, kAndroidOpts_SkDescriptorTag, &androidBuffer);
michael@0 1920 #endif
michael@0 1921
michael@0 1922 if (pe) {
michael@0 1923 add_flattenable(desc1, kPathEffect_SkDescriptorTag, &peBuffer);
michael@0 1924 add_flattenable(desc2, kPathEffect_SkDescriptorTag, &peBuffer);
michael@0 1925 }
michael@0 1926 if (mf) {
michael@0 1927 add_flattenable(desc1, kMaskFilter_SkDescriptorTag, &mfBuffer);
michael@0 1928 add_flattenable(desc2, kMaskFilter_SkDescriptorTag, &mfBuffer);
michael@0 1929 }
michael@0 1930 if (ra) {
michael@0 1931 add_flattenable(desc1, kRasterizer_SkDescriptorTag, &raBuffer);
michael@0 1932 add_flattenable(desc2, kRasterizer_SkDescriptorTag, &raBuffer);
michael@0 1933 }
michael@0 1934
michael@0 1935 SkASSERT(descSize == desc1->getLength());
michael@0 1936 SkASSERT(descSize == desc2->getLength());
michael@0 1937 desc1->computeChecksum();
michael@0 1938 desc2->computeChecksum();
michael@0 1939 SkASSERT(!memcmp(desc, desc1, descSize));
michael@0 1940 SkASSERT(!memcmp(desc, desc2, descSize));
michael@0 1941 }
michael@0 1942 #endif
michael@0 1943
michael@0 1944 proc(fTypeface, desc, context);
michael@0 1945 }
michael@0 1946
michael@0 1947 SkGlyphCache* SkPaint::detachCache(const SkDeviceProperties* deviceProperties,
michael@0 1948 const SkMatrix* deviceMatrix) const {
michael@0 1949 SkGlyphCache* cache;
michael@0 1950 this->descriptorProc(deviceProperties, deviceMatrix, DetachDescProc, &cache, false);
michael@0 1951 return cache;
michael@0 1952 }
michael@0 1953
michael@0 1954 /**
michael@0 1955 * Expands fDeviceGamma, fPaintGamma, fContrast, and fLumBits into a mask pre-blend.
michael@0 1956 */
michael@0 1957 //static
michael@0 1958 SkMaskGamma::PreBlend SkScalerContext::GetMaskPreBlend(const SkScalerContext::Rec& rec) {
michael@0 1959 SkAutoMutexAcquire ama(gMaskGammaCacheMutex);
michael@0 1960 const SkMaskGamma& maskGamma = cachedMaskGamma(rec.getContrast(),
michael@0 1961 rec.getPaintGamma(),
michael@0 1962 rec.getDeviceGamma());
michael@0 1963 return maskGamma.preBlend(rec.getLuminanceColor());
michael@0 1964 }
michael@0 1965
michael@0 1966 ///////////////////////////////////////////////////////////////////////////////
michael@0 1967
michael@0 1968 #include "SkStream.h"
michael@0 1969
michael@0 1970 static uintptr_t asint(const void* p) {
michael@0 1971 return reinterpret_cast<uintptr_t>(p);
michael@0 1972 }
michael@0 1973
michael@0 1974 union Scalar32 {
michael@0 1975 SkScalar fScalar;
michael@0 1976 uint32_t f32;
michael@0 1977 };
michael@0 1978
michael@0 1979 static uint32_t* write_scalar(uint32_t* ptr, SkScalar value) {
michael@0 1980 SkASSERT(sizeof(SkScalar) == sizeof(uint32_t));
michael@0 1981 Scalar32 tmp;
michael@0 1982 tmp.fScalar = value;
michael@0 1983 *ptr = tmp.f32;
michael@0 1984 return ptr + 1;
michael@0 1985 }
michael@0 1986
michael@0 1987 static SkScalar read_scalar(const uint32_t*& ptr) {
michael@0 1988 SkASSERT(sizeof(SkScalar) == sizeof(uint32_t));
michael@0 1989 Scalar32 tmp;
michael@0 1990 tmp.f32 = *ptr++;
michael@0 1991 return tmp.fScalar;
michael@0 1992 }
michael@0 1993
michael@0 1994 static uint32_t pack_4(unsigned a, unsigned b, unsigned c, unsigned d) {
michael@0 1995 SkASSERT(a == (uint8_t)a);
michael@0 1996 SkASSERT(b == (uint8_t)b);
michael@0 1997 SkASSERT(c == (uint8_t)c);
michael@0 1998 SkASSERT(d == (uint8_t)d);
michael@0 1999 return (a << 24) | (b << 16) | (c << 8) | d;
michael@0 2000 }
michael@0 2001
michael@0 2002 enum FlatFlags {
michael@0 2003 kHasTypeface_FlatFlag = 0x01,
michael@0 2004 kHasEffects_FlatFlag = 0x02,
michael@0 2005 kHasNonDefaultPaintOptionsAndroid_FlatFlag = 0x04,
michael@0 2006 };
michael@0 2007
michael@0 2008 // The size of a flat paint's POD fields
michael@0 2009 static const uint32_t kPODPaintSize = 5 * sizeof(SkScalar) +
michael@0 2010 1 * sizeof(SkColor) +
michael@0 2011 1 * sizeof(uint16_t) +
michael@0 2012 6 * sizeof(uint8_t);
michael@0 2013
michael@0 2014 /* To save space/time, we analyze the paint, and write a truncated version of
michael@0 2015 it if there are not tricky elements like shaders, etc.
michael@0 2016 */
michael@0 2017 void SkPaint::flatten(SkWriteBuffer& buffer) const {
michael@0 2018 uint8_t flatFlags = 0;
michael@0 2019 if (this->getTypeface()) {
michael@0 2020 flatFlags |= kHasTypeface_FlatFlag;
michael@0 2021 }
michael@0 2022 if (asint(this->getPathEffect()) |
michael@0 2023 asint(this->getShader()) |
michael@0 2024 asint(this->getXfermode()) |
michael@0 2025 asint(this->getMaskFilter()) |
michael@0 2026 asint(this->getColorFilter()) |
michael@0 2027 asint(this->getRasterizer()) |
michael@0 2028 asint(this->getLooper()) |
michael@0 2029 asint(this->getAnnotation()) |
michael@0 2030 asint(this->getImageFilter())) {
michael@0 2031 flatFlags |= kHasEffects_FlatFlag;
michael@0 2032 }
michael@0 2033 #ifdef SK_BUILD_FOR_ANDROID
michael@0 2034 if (this->getPaintOptionsAndroid() != SkPaintOptionsAndroid()) {
michael@0 2035 flatFlags |= kHasNonDefaultPaintOptionsAndroid_FlatFlag;
michael@0 2036 }
michael@0 2037 #endif
michael@0 2038
michael@0 2039 SkASSERT(SkAlign4(kPODPaintSize) == kPODPaintSize);
michael@0 2040 uint32_t* ptr = buffer.reserve(kPODPaintSize);
michael@0 2041
michael@0 2042 ptr = write_scalar(ptr, this->getTextSize());
michael@0 2043 ptr = write_scalar(ptr, this->getTextScaleX());
michael@0 2044 ptr = write_scalar(ptr, this->getTextSkewX());
michael@0 2045 ptr = write_scalar(ptr, this->getStrokeWidth());
michael@0 2046 ptr = write_scalar(ptr, this->getStrokeMiter());
michael@0 2047 *ptr++ = this->getColor();
michael@0 2048 // previously flags:16, textAlign:8, flatFlags:8
michael@0 2049 // now flags:16, hinting:4, textAlign:4, flatFlags:8
michael@0 2050 *ptr++ = (this->getFlags() << 16) |
michael@0 2051 // hinting added later. 0 in this nibble means use the default.
michael@0 2052 ((this->getHinting()+1) << 12) |
michael@0 2053 (this->getTextAlign() << 8) |
michael@0 2054 flatFlags;
michael@0 2055 *ptr++ = pack_4(this->getStrokeCap(), this->getStrokeJoin(),
michael@0 2056 this->getStyle(), this->getTextEncoding());
michael@0 2057
michael@0 2058 // now we're done with ptr and the (pre)reserved space. If we need to write
michael@0 2059 // additional fields, use the buffer directly
michael@0 2060 if (flatFlags & kHasTypeface_FlatFlag) {
michael@0 2061 buffer.writeTypeface(this->getTypeface());
michael@0 2062 }
michael@0 2063 if (flatFlags & kHasEffects_FlatFlag) {
michael@0 2064 buffer.writeFlattenable(this->getPathEffect());
michael@0 2065 buffer.writeFlattenable(this->getShader());
michael@0 2066 buffer.writeFlattenable(this->getXfermode());
michael@0 2067 buffer.writeFlattenable(this->getMaskFilter());
michael@0 2068 buffer.writeFlattenable(this->getColorFilter());
michael@0 2069 buffer.writeFlattenable(this->getRasterizer());
michael@0 2070 buffer.writeFlattenable(this->getLooper());
michael@0 2071 buffer.writeFlattenable(this->getImageFilter());
michael@0 2072
michael@0 2073 if (fAnnotation) {
michael@0 2074 buffer.writeBool(true);
michael@0 2075 fAnnotation->writeToBuffer(buffer);
michael@0 2076 } else {
michael@0 2077 buffer.writeBool(false);
michael@0 2078 }
michael@0 2079 }
michael@0 2080 #ifdef SK_BUILD_FOR_ANDROID
michael@0 2081 if (flatFlags & kHasNonDefaultPaintOptionsAndroid_FlatFlag) {
michael@0 2082 this->getPaintOptionsAndroid().flatten(buffer);
michael@0 2083 }
michael@0 2084 #endif
michael@0 2085 }
michael@0 2086
michael@0 2087 void SkPaint::unflatten(SkReadBuffer& buffer) {
michael@0 2088 uint8_t flatFlags = 0;
michael@0 2089 SkASSERT(SkAlign4(kPODPaintSize) == kPODPaintSize);
michael@0 2090 const void* podData = buffer.skip(kPODPaintSize);
michael@0 2091 const uint32_t* pod = reinterpret_cast<const uint32_t*>(podData);
michael@0 2092
michael@0 2093 // the order we read must match the order we wrote in flatten()
michael@0 2094 this->setTextSize(read_scalar(pod));
michael@0 2095 this->setTextScaleX(read_scalar(pod));
michael@0 2096 this->setTextSkewX(read_scalar(pod));
michael@0 2097 this->setStrokeWidth(read_scalar(pod));
michael@0 2098 this->setStrokeMiter(read_scalar(pod));
michael@0 2099 this->setColor(*pod++);
michael@0 2100
michael@0 2101 // previously flags:16, textAlign:8, flatFlags:8
michael@0 2102 // now flags:16, hinting:4, textAlign:4, flatFlags:8
michael@0 2103 uint32_t tmp = *pod++;
michael@0 2104 this->setFlags(tmp >> 16);
michael@0 2105
michael@0 2106 // hinting added later. 0 in this nibble means use the default.
michael@0 2107 uint32_t hinting = (tmp >> 12) & 0xF;
michael@0 2108 this->setHinting(0 == hinting ? kNormal_Hinting : static_cast<Hinting>(hinting-1));
michael@0 2109
michael@0 2110 this->setTextAlign(static_cast<Align>((tmp >> 8) & 0xF));
michael@0 2111
michael@0 2112 flatFlags = tmp & 0xFF;
michael@0 2113
michael@0 2114 tmp = *pod++;
michael@0 2115 this->setStrokeCap(static_cast<Cap>((tmp >> 24) & 0xFF));
michael@0 2116 this->setStrokeJoin(static_cast<Join>((tmp >> 16) & 0xFF));
michael@0 2117 this->setStyle(static_cast<Style>((tmp >> 8) & 0xFF));
michael@0 2118 this->setTextEncoding(static_cast<TextEncoding>((tmp >> 0) & 0xFF));
michael@0 2119
michael@0 2120 if (flatFlags & kHasTypeface_FlatFlag) {
michael@0 2121 this->setTypeface(buffer.readTypeface());
michael@0 2122 } else {
michael@0 2123 this->setTypeface(NULL);
michael@0 2124 }
michael@0 2125
michael@0 2126 if (flatFlags & kHasEffects_FlatFlag) {
michael@0 2127 SkSafeUnref(this->setPathEffect(buffer.readPathEffect()));
michael@0 2128 SkSafeUnref(this->setShader(buffer.readShader()));
michael@0 2129 SkSafeUnref(this->setXfermode(buffer.readXfermode()));
michael@0 2130 SkSafeUnref(this->setMaskFilter(buffer.readMaskFilter()));
michael@0 2131 SkSafeUnref(this->setColorFilter(buffer.readColorFilter()));
michael@0 2132 SkSafeUnref(this->setRasterizer(buffer.readRasterizer()));
michael@0 2133 SkSafeUnref(this->setLooper(buffer.readDrawLooper()));
michael@0 2134 SkSafeUnref(this->setImageFilter(buffer.readImageFilter()));
michael@0 2135
michael@0 2136 if (buffer.readBool()) {
michael@0 2137 this->setAnnotation(SkAnnotation::Create(buffer))->unref();
michael@0 2138 }
michael@0 2139 } else {
michael@0 2140 this->setPathEffect(NULL);
michael@0 2141 this->setShader(NULL);
michael@0 2142 this->setXfermode(NULL);
michael@0 2143 this->setMaskFilter(NULL);
michael@0 2144 this->setColorFilter(NULL);
michael@0 2145 this->setRasterizer(NULL);
michael@0 2146 this->setLooper(NULL);
michael@0 2147 this->setImageFilter(NULL);
michael@0 2148 }
michael@0 2149
michael@0 2150 #ifdef SK_BUILD_FOR_ANDROID
michael@0 2151 this->setPaintOptionsAndroid(SkPaintOptionsAndroid());
michael@0 2152 #endif
michael@0 2153 if (flatFlags & kHasNonDefaultPaintOptionsAndroid_FlatFlag) {
michael@0 2154 SkPaintOptionsAndroid options;
michael@0 2155 options.unflatten(buffer);
michael@0 2156 #ifdef SK_BUILD_FOR_ANDROID
michael@0 2157 this->setPaintOptionsAndroid(options);
michael@0 2158 #endif
michael@0 2159 }
michael@0 2160 }
michael@0 2161
michael@0 2162 ///////////////////////////////////////////////////////////////////////////////
michael@0 2163
michael@0 2164 SkShader* SkPaint::setShader(SkShader* shader) {
michael@0 2165 GEN_ID_INC_EVAL(shader != fShader);
michael@0 2166 SkRefCnt_SafeAssign(fShader, shader);
michael@0 2167 fDirtyBits = set_mask(fDirtyBits, kShader_DirtyBit, shader != NULL);
michael@0 2168 return shader;
michael@0 2169 }
michael@0 2170
michael@0 2171 SkColorFilter* SkPaint::setColorFilter(SkColorFilter* filter) {
michael@0 2172 GEN_ID_INC_EVAL(filter != fColorFilter);
michael@0 2173 SkRefCnt_SafeAssign(fColorFilter, filter);
michael@0 2174 fDirtyBits = set_mask(fDirtyBits, kColorFilter_DirtyBit, filter != NULL);
michael@0 2175 return filter;
michael@0 2176 }
michael@0 2177
michael@0 2178 SkXfermode* SkPaint::setXfermode(SkXfermode* mode) {
michael@0 2179 GEN_ID_INC_EVAL(mode != fXfermode);
michael@0 2180 SkRefCnt_SafeAssign(fXfermode, mode);
michael@0 2181 fDirtyBits = set_mask(fDirtyBits, kXfermode_DirtyBit, mode != NULL);
michael@0 2182 return mode;
michael@0 2183 }
michael@0 2184
michael@0 2185 SkXfermode* SkPaint::setXfermodeMode(SkXfermode::Mode mode) {
michael@0 2186 SkSafeUnref(fXfermode);
michael@0 2187 fXfermode = SkXfermode::Create(mode);
michael@0 2188 GEN_ID_INC;
michael@0 2189 fDirtyBits = set_mask(fDirtyBits, kXfermode_DirtyBit, fXfermode != NULL);
michael@0 2190 return fXfermode;
michael@0 2191 }
michael@0 2192
michael@0 2193 SkPathEffect* SkPaint::setPathEffect(SkPathEffect* effect) {
michael@0 2194 GEN_ID_INC_EVAL(effect != fPathEffect);
michael@0 2195 SkRefCnt_SafeAssign(fPathEffect, effect);
michael@0 2196 fDirtyBits = set_mask(fDirtyBits, kPathEffect_DirtyBit, effect != NULL);
michael@0 2197 return effect;
michael@0 2198 }
michael@0 2199
michael@0 2200 SkMaskFilter* SkPaint::setMaskFilter(SkMaskFilter* filter) {
michael@0 2201 GEN_ID_INC_EVAL(filter != fMaskFilter);
michael@0 2202 SkRefCnt_SafeAssign(fMaskFilter, filter);
michael@0 2203 fDirtyBits = set_mask(fDirtyBits, kMaskFilter_DirtyBit, filter != NULL);
michael@0 2204 return filter;
michael@0 2205 }
michael@0 2206
michael@0 2207 ///////////////////////////////////////////////////////////////////////////////
michael@0 2208
michael@0 2209 bool SkPaint::getFillPath(const SkPath& src, SkPath* dst,
michael@0 2210 const SkRect* cullRect) const {
michael@0 2211 SkStrokeRec rec(*this);
michael@0 2212
michael@0 2213 const SkPath* srcPtr = &src;
michael@0 2214 SkPath tmpPath;
michael@0 2215
michael@0 2216 if (fPathEffect && fPathEffect->filterPath(&tmpPath, src, &rec, cullRect)) {
michael@0 2217 srcPtr = &tmpPath;
michael@0 2218 }
michael@0 2219
michael@0 2220 if (!rec.applyToPath(dst, *srcPtr)) {
michael@0 2221 if (srcPtr == &tmpPath) {
michael@0 2222 // If path's were copy-on-write, this trick would not be needed.
michael@0 2223 // As it is, we want to save making a deep-copy from tmpPath -> dst
michael@0 2224 // since we know we're just going to delete tmpPath when we return,
michael@0 2225 // so the swap saves that copy.
michael@0 2226 dst->swap(tmpPath);
michael@0 2227 } else {
michael@0 2228 *dst = *srcPtr;
michael@0 2229 }
michael@0 2230 }
michael@0 2231 return !rec.isHairlineStyle();
michael@0 2232 }
michael@0 2233
michael@0 2234 const SkRect& SkPaint::doComputeFastBounds(const SkRect& origSrc,
michael@0 2235 SkRect* storage,
michael@0 2236 Style style) const {
michael@0 2237 SkASSERT(storage);
michael@0 2238
michael@0 2239 const SkRect* src = &origSrc;
michael@0 2240
michael@0 2241 if (this->getLooper()) {
michael@0 2242 SkASSERT(this->getLooper()->canComputeFastBounds(*this));
michael@0 2243 this->getLooper()->computeFastBounds(*this, *src, storage);
michael@0 2244 return *storage;
michael@0 2245 }
michael@0 2246
michael@0 2247 SkRect tmpSrc;
michael@0 2248 if (this->getPathEffect()) {
michael@0 2249 this->getPathEffect()->computeFastBounds(&tmpSrc, origSrc);
michael@0 2250 src = &tmpSrc;
michael@0 2251 }
michael@0 2252
michael@0 2253 if (kFill_Style != style) {
michael@0 2254 // since we're stroked, outset the rect by the radius (and join type)
michael@0 2255 SkScalar radius = SkScalarHalf(this->getStrokeWidth());
michael@0 2256 if (0 == radius) { // hairline
michael@0 2257 radius = SK_Scalar1;
michael@0 2258 } else if (this->getStrokeJoin() == SkPaint::kMiter_Join) {
michael@0 2259 SkScalar scale = this->getStrokeMiter();
michael@0 2260 if (scale > SK_Scalar1) {
michael@0 2261 radius = SkScalarMul(radius, scale);
michael@0 2262 }
michael@0 2263 }
michael@0 2264 storage->set(src->fLeft - radius, src->fTop - radius,
michael@0 2265 src->fRight + radius, src->fBottom + radius);
michael@0 2266 } else {
michael@0 2267 *storage = *src;
michael@0 2268 }
michael@0 2269
michael@0 2270 if (this->getMaskFilter()) {
michael@0 2271 this->getMaskFilter()->computeFastBounds(*storage, storage);
michael@0 2272 }
michael@0 2273
michael@0 2274 if (this->getImageFilter()) {
michael@0 2275 this->getImageFilter()->computeFastBounds(*storage, storage);
michael@0 2276 }
michael@0 2277
michael@0 2278 return *storage;
michael@0 2279 }
michael@0 2280
michael@0 2281 #ifndef SK_IGNORE_TO_STRING
michael@0 2282 void SkPaint::toString(SkString* str) const {
michael@0 2283 str->append("<dl><dt>SkPaint:</dt><dd><dl>");
michael@0 2284
michael@0 2285 SkTypeface* typeface = this->getTypeface();
michael@0 2286 if (NULL != typeface) {
michael@0 2287 SkDynamicMemoryWStream ostream;
michael@0 2288 typeface->serialize(&ostream);
michael@0 2289 SkAutoTUnref<SkData> data(ostream.copyToData());
michael@0 2290
michael@0 2291 SkMemoryStream stream(data);
michael@0 2292 SkFontDescriptor descriptor(&stream);
michael@0 2293
michael@0 2294 str->append("<dt>Font Family Name:</dt><dd>");
michael@0 2295 str->append(descriptor.getFamilyName());
michael@0 2296 str->append("</dd><dt>Font Full Name:</dt><dd>");
michael@0 2297 str->append(descriptor.getFullName());
michael@0 2298 str->append("</dd><dt>Font PS Name:</dt><dd>");
michael@0 2299 str->append(descriptor.getPostscriptName());
michael@0 2300 str->append("</dd><dt>Font File Name:</dt><dd>");
michael@0 2301 str->append(descriptor.getFontFileName());
michael@0 2302 str->append("</dd>");
michael@0 2303 }
michael@0 2304
michael@0 2305 str->append("<dt>TextSize:</dt><dd>");
michael@0 2306 str->appendScalar(this->getTextSize());
michael@0 2307 str->append("</dd>");
michael@0 2308
michael@0 2309 str->append("<dt>TextScaleX:</dt><dd>");
michael@0 2310 str->appendScalar(this->getTextScaleX());
michael@0 2311 str->append("</dd>");
michael@0 2312
michael@0 2313 str->append("<dt>TextSkewX:</dt><dd>");
michael@0 2314 str->appendScalar(this->getTextSkewX());
michael@0 2315 str->append("</dd>");
michael@0 2316
michael@0 2317 SkPathEffect* pathEffect = this->getPathEffect();
michael@0 2318 if (NULL != pathEffect) {
michael@0 2319 str->append("<dt>PathEffect:</dt><dd>");
michael@0 2320 str->append("</dd>");
michael@0 2321 }
michael@0 2322
michael@0 2323 SkShader* shader = this->getShader();
michael@0 2324 if (NULL != shader) {
michael@0 2325 str->append("<dt>Shader:</dt><dd>");
michael@0 2326 shader->toString(str);
michael@0 2327 str->append("</dd>");
michael@0 2328 }
michael@0 2329
michael@0 2330 SkXfermode* xfer = this->getXfermode();
michael@0 2331 if (NULL != xfer) {
michael@0 2332 str->append("<dt>Xfermode:</dt><dd>");
michael@0 2333 xfer->toString(str);
michael@0 2334 str->append("</dd>");
michael@0 2335 }
michael@0 2336
michael@0 2337 SkMaskFilter* maskFilter = this->getMaskFilter();
michael@0 2338 if (NULL != maskFilter) {
michael@0 2339 str->append("<dt>MaskFilter:</dt><dd>");
michael@0 2340 maskFilter->toString(str);
michael@0 2341 str->append("</dd>");
michael@0 2342 }
michael@0 2343
michael@0 2344 SkColorFilter* colorFilter = this->getColorFilter();
michael@0 2345 if (NULL != colorFilter) {
michael@0 2346 str->append("<dt>ColorFilter:</dt><dd>");
michael@0 2347 colorFilter->toString(str);
michael@0 2348 str->append("</dd>");
michael@0 2349 }
michael@0 2350
michael@0 2351 SkRasterizer* rasterizer = this->getRasterizer();
michael@0 2352 if (NULL != rasterizer) {
michael@0 2353 str->append("<dt>Rasterizer:</dt><dd>");
michael@0 2354 str->append("</dd>");
michael@0 2355 }
michael@0 2356
michael@0 2357 SkDrawLooper* looper = this->getLooper();
michael@0 2358 if (NULL != looper) {
michael@0 2359 str->append("<dt>DrawLooper:</dt><dd>");
michael@0 2360 looper->toString(str);
michael@0 2361 str->append("</dd>");
michael@0 2362 }
michael@0 2363
michael@0 2364 SkImageFilter* imageFilter = this->getImageFilter();
michael@0 2365 if (NULL != imageFilter) {
michael@0 2366 str->append("<dt>ImageFilter:</dt><dd>");
michael@0 2367 str->append("</dd>");
michael@0 2368 }
michael@0 2369
michael@0 2370 SkAnnotation* annotation = this->getAnnotation();
michael@0 2371 if (NULL != annotation) {
michael@0 2372 str->append("<dt>Annotation:</dt><dd>");
michael@0 2373 str->append("</dd>");
michael@0 2374 }
michael@0 2375
michael@0 2376 str->append("<dt>Color:</dt><dd>0x");
michael@0 2377 SkColor color = this->getColor();
michael@0 2378 str->appendHex(color);
michael@0 2379 str->append("</dd>");
michael@0 2380
michael@0 2381 str->append("<dt>Stroke Width:</dt><dd>");
michael@0 2382 str->appendScalar(this->getStrokeWidth());
michael@0 2383 str->append("</dd>");
michael@0 2384
michael@0 2385 str->append("<dt>Stroke Miter:</dt><dd>");
michael@0 2386 str->appendScalar(this->getStrokeMiter());
michael@0 2387 str->append("</dd>");
michael@0 2388
michael@0 2389 str->append("<dt>Flags:</dt><dd>(");
michael@0 2390 if (this->getFlags()) {
michael@0 2391 bool needSeparator = false;
michael@0 2392 SkAddFlagToString(str, this->isAntiAlias(), "AntiAlias", &needSeparator);
michael@0 2393 SkAddFlagToString(str, this->isDither(), "Dither", &needSeparator);
michael@0 2394 SkAddFlagToString(str, this->isUnderlineText(), "UnderlineText", &needSeparator);
michael@0 2395 SkAddFlagToString(str, this->isStrikeThruText(), "StrikeThruText", &needSeparator);
michael@0 2396 SkAddFlagToString(str, this->isFakeBoldText(), "FakeBoldText", &needSeparator);
michael@0 2397 SkAddFlagToString(str, this->isLinearText(), "LinearText", &needSeparator);
michael@0 2398 SkAddFlagToString(str, this->isSubpixelText(), "SubpixelText", &needSeparator);
michael@0 2399 SkAddFlagToString(str, this->isDevKernText(), "DevKernText", &needSeparator);
michael@0 2400 SkAddFlagToString(str, this->isLCDRenderText(), "LCDRenderText", &needSeparator);
michael@0 2401 SkAddFlagToString(str, this->isEmbeddedBitmapText(),
michael@0 2402 "EmbeddedBitmapText", &needSeparator);
michael@0 2403 SkAddFlagToString(str, this->isAutohinted(), "Autohinted", &needSeparator);
michael@0 2404 SkAddFlagToString(str, this->isVerticalText(), "VerticalText", &needSeparator);
michael@0 2405 SkAddFlagToString(str, SkToBool(this->getFlags() & SkPaint::kGenA8FromLCD_Flag),
michael@0 2406 "GenA8FromLCD", &needSeparator);
michael@0 2407 } else {
michael@0 2408 str->append("None");
michael@0 2409 }
michael@0 2410 str->append(")</dd>");
michael@0 2411
michael@0 2412 str->append("<dt>FilterLevel:</dt><dd>");
michael@0 2413 static const char* gFilterLevelStrings[] = { "None", "Low", "Medium", "High" };
michael@0 2414 str->append(gFilterLevelStrings[this->getFilterLevel()]);
michael@0 2415 str->append("</dd>");
michael@0 2416
michael@0 2417 str->append("<dt>TextAlign:</dt><dd>");
michael@0 2418 static const char* gTextAlignStrings[SkPaint::kAlignCount] = { "Left", "Center", "Right" };
michael@0 2419 str->append(gTextAlignStrings[this->getTextAlign()]);
michael@0 2420 str->append("</dd>");
michael@0 2421
michael@0 2422 str->append("<dt>CapType:</dt><dd>");
michael@0 2423 static const char* gStrokeCapStrings[SkPaint::kCapCount] = { "Butt", "Round", "Square" };
michael@0 2424 str->append(gStrokeCapStrings[this->getStrokeCap()]);
michael@0 2425 str->append("</dd>");
michael@0 2426
michael@0 2427 str->append("<dt>JoinType:</dt><dd>");
michael@0 2428 static const char* gJoinStrings[SkPaint::kJoinCount] = { "Miter", "Round", "Bevel" };
michael@0 2429 str->append(gJoinStrings[this->getStrokeJoin()]);
michael@0 2430 str->append("</dd>");
michael@0 2431
michael@0 2432 str->append("<dt>Style:</dt><dd>");
michael@0 2433 static const char* gStyleStrings[SkPaint::kStyleCount] = { "Fill", "Stroke", "StrokeAndFill" };
michael@0 2434 str->append(gStyleStrings[this->getStyle()]);
michael@0 2435 str->append("</dd>");
michael@0 2436
michael@0 2437 str->append("<dt>TextEncoding:</dt><dd>");
michael@0 2438 static const char* gTextEncodingStrings[] = { "UTF8", "UTF16", "UTF32", "GlyphID" };
michael@0 2439 str->append(gTextEncodingStrings[this->getTextEncoding()]);
michael@0 2440 str->append("</dd>");
michael@0 2441
michael@0 2442 str->append("<dt>Hinting:</dt><dd>");
michael@0 2443 static const char* gHintingStrings[] = { "None", "Slight", "Normal", "Full" };
michael@0 2444 str->append(gHintingStrings[this->getHinting()]);
michael@0 2445 str->append("</dd>");
michael@0 2446
michael@0 2447 str->append("</dd></dl></dl>");
michael@0 2448 }
michael@0 2449 #endif
michael@0 2450
michael@0 2451 ///////////////////////////////////////////////////////////////////////////////
michael@0 2452
michael@0 2453 static bool has_thick_frame(const SkPaint& paint) {
michael@0 2454 return paint.getStrokeWidth() > 0 &&
michael@0 2455 paint.getStyle() != SkPaint::kFill_Style;
michael@0 2456 }
michael@0 2457
michael@0 2458 SkTextToPathIter::SkTextToPathIter( const char text[], size_t length,
michael@0 2459 const SkPaint& paint,
michael@0 2460 bool applyStrokeAndPathEffects)
michael@0 2461 : fPaint(paint) {
michael@0 2462 fGlyphCacheProc = paint.getMeasureCacheProc(SkPaint::kForward_TextBufferDirection,
michael@0 2463 true);
michael@0 2464
michael@0 2465 fPaint.setLinearText(true);
michael@0 2466 fPaint.setMaskFilter(NULL); // don't want this affecting our path-cache lookup
michael@0 2467
michael@0 2468 if (fPaint.getPathEffect() == NULL && !has_thick_frame(fPaint)) {
michael@0 2469 applyStrokeAndPathEffects = false;
michael@0 2470 }
michael@0 2471
michael@0 2472 // can't use our canonical size if we need to apply patheffects
michael@0 2473 if (fPaint.getPathEffect() == NULL) {
michael@0 2474 fPaint.setTextSize(SkIntToScalar(SkPaint::kCanonicalTextSizeForPaths));
michael@0 2475 fScale = paint.getTextSize() / SkPaint::kCanonicalTextSizeForPaths;
michael@0 2476 if (has_thick_frame(fPaint)) {
michael@0 2477 fPaint.setStrokeWidth(SkScalarDiv(fPaint.getStrokeWidth(), fScale));
michael@0 2478 }
michael@0 2479 } else {
michael@0 2480 fScale = SK_Scalar1;
michael@0 2481 }
michael@0 2482
michael@0 2483 if (!applyStrokeAndPathEffects) {
michael@0 2484 fPaint.setStyle(SkPaint::kFill_Style);
michael@0 2485 fPaint.setPathEffect(NULL);
michael@0 2486 }
michael@0 2487
michael@0 2488 fCache = fPaint.detachCache(NULL, NULL);
michael@0 2489
michael@0 2490 SkPaint::Style style = SkPaint::kFill_Style;
michael@0 2491 SkPathEffect* pe = NULL;
michael@0 2492
michael@0 2493 if (!applyStrokeAndPathEffects) {
michael@0 2494 style = paint.getStyle(); // restore
michael@0 2495 pe = paint.getPathEffect(); // restore
michael@0 2496 }
michael@0 2497 fPaint.setStyle(style);
michael@0 2498 fPaint.setPathEffect(pe);
michael@0 2499 fPaint.setMaskFilter(paint.getMaskFilter()); // restore
michael@0 2500
michael@0 2501 // now compute fXOffset if needed
michael@0 2502
michael@0 2503 SkScalar xOffset = 0;
michael@0 2504 if (paint.getTextAlign() != SkPaint::kLeft_Align) { // need to measure first
michael@0 2505 int count;
michael@0 2506 SkScalar width = SkScalarMul(fPaint.measure_text(fCache, text, length,
michael@0 2507 &count, NULL), fScale);
michael@0 2508 if (paint.getTextAlign() == SkPaint::kCenter_Align) {
michael@0 2509 width = SkScalarHalf(width);
michael@0 2510 }
michael@0 2511 xOffset = -width;
michael@0 2512 }
michael@0 2513 fXPos = xOffset;
michael@0 2514 fPrevAdvance = 0;
michael@0 2515
michael@0 2516 fText = text;
michael@0 2517 fStop = text + length;
michael@0 2518
michael@0 2519 fXYIndex = paint.isVerticalText() ? 1 : 0;
michael@0 2520 }
michael@0 2521
michael@0 2522 SkTextToPathIter::~SkTextToPathIter() {
michael@0 2523 SkGlyphCache::AttachCache(fCache);
michael@0 2524 }
michael@0 2525
michael@0 2526 bool SkTextToPathIter::next(const SkPath** path, SkScalar* xpos) {
michael@0 2527 if (fText < fStop) {
michael@0 2528 const SkGlyph& glyph = fGlyphCacheProc(fCache, &fText);
michael@0 2529
michael@0 2530 fXPos += SkScalarMul(SkFixedToScalar(fPrevAdvance + fAutoKern.adjust(glyph)), fScale);
michael@0 2531 fPrevAdvance = advance(glyph, fXYIndex); // + fPaint.getTextTracking();
michael@0 2532
michael@0 2533 if (glyph.fWidth) {
michael@0 2534 if (path) {
michael@0 2535 *path = fCache->findPath(glyph);
michael@0 2536 }
michael@0 2537 } else {
michael@0 2538 if (path) {
michael@0 2539 *path = NULL;
michael@0 2540 }
michael@0 2541 }
michael@0 2542 if (xpos) {
michael@0 2543 *xpos = fXPos;
michael@0 2544 }
michael@0 2545 return true;
michael@0 2546 }
michael@0 2547 return false;
michael@0 2548 }
michael@0 2549
michael@0 2550 ///////////////////////////////////////////////////////////////////////////////
michael@0 2551
michael@0 2552 bool SkPaint::nothingToDraw() const {
michael@0 2553 if (fLooper) {
michael@0 2554 return false;
michael@0 2555 }
michael@0 2556 SkXfermode::Mode mode;
michael@0 2557 if (SkXfermode::AsMode(fXfermode, &mode)) {
michael@0 2558 switch (mode) {
michael@0 2559 case SkXfermode::kSrcOver_Mode:
michael@0 2560 case SkXfermode::kSrcATop_Mode:
michael@0 2561 case SkXfermode::kDstOut_Mode:
michael@0 2562 case SkXfermode::kDstOver_Mode:
michael@0 2563 case SkXfermode::kPlus_Mode:
michael@0 2564 return 0 == this->getAlpha();
michael@0 2565 case SkXfermode::kDst_Mode:
michael@0 2566 return true;
michael@0 2567 default:
michael@0 2568 break;
michael@0 2569 }
michael@0 2570 }
michael@0 2571 return false;
michael@0 2572 }
michael@0 2573
michael@0 2574 void SkPaint::setBitfields(uint32_t bitfields) {
michael@0 2575 fBitfields = bitfields;
michael@0 2576 fDirtyBits |= kBitfields_DirtyBit;
michael@0 2577 }
michael@0 2578
michael@0 2579 inline static unsigned popcount(uint8_t x) {
michael@0 2580 // As in Hacker's delight, adapted for just 8 bits.
michael@0 2581 x = (x & 0x55) + ((x >> 1) & 0x55); // a b c d w x y z -> a+b c+d w+x y+z
michael@0 2582 x = (x & 0x33) + ((x >> 2) & 0x33); // a+b c+d w+x y+z -> a+b+c+d w+x+y+z
michael@0 2583 x = (x & 0x0F) + ((x >> 4) & 0x0F); // a+b+c+d w+x+y+z -> a+b+c+d+w+x+y+z
michael@0 2584 return x;
michael@0 2585 }
michael@0 2586
michael@0 2587 void SkPaint::FlatteningTraits::Flatten(SkWriteBuffer& buffer, const SkPaint& paint) {
michael@0 2588 const uint32_t dirty = paint.fDirtyBits;
michael@0 2589
michael@0 2590 // Each of the low 7 dirty bits corresponds to a 4-byte flat value, plus one for the dirty bits.
michael@0 2591 const size_t flatBytes = 4 * (popcount(dirty & 127) + 1);
michael@0 2592 SkASSERT(flatBytes <= 32);
michael@0 2593 uint32_t* u32 = buffer.reserve(flatBytes);
michael@0 2594 *u32++ = dirty;
michael@0 2595 if (dirty == 0) {
michael@0 2596 return;
michael@0 2597 }
michael@0 2598
michael@0 2599 #define F(dst, field) if (dirty & k##field##_DirtyBit) *dst++ = paint.get##field()
michael@0 2600 F(u32, Color);
michael@0 2601 F(u32, Bitfields);
michael@0 2602 SkScalar* f32 = reinterpret_cast<SkScalar*>(u32);
michael@0 2603 F(f32, TextSize);
michael@0 2604 F(f32, TextScaleX);
michael@0 2605 F(f32, TextSkewX);
michael@0 2606 F(f32, StrokeWidth);
michael@0 2607 F(f32, StrokeMiter);
michael@0 2608 #undef F
michael@0 2609 #define F(field) if (dirty & k##field##_DirtyBit) buffer.writeFlattenable(paint.get##field())
michael@0 2610 F(PathEffect);
michael@0 2611 F(Shader);
michael@0 2612 F(Xfermode);
michael@0 2613 F(MaskFilter);
michael@0 2614 F(ColorFilter);
michael@0 2615 F(Rasterizer);
michael@0 2616 F(Looper);
michael@0 2617 F(ImageFilter);
michael@0 2618 #undef F
michael@0 2619 if (dirty & kTypeface_DirtyBit) buffer.writeTypeface(paint.getTypeface());
michael@0 2620 if (dirty & kAnnotation_DirtyBit) paint.getAnnotation()->writeToBuffer(buffer);
michael@0 2621 #ifdef SK_BUILD_FOR_ANDROID
michael@0 2622 if (dirty & kPaintOptionsAndroid_DirtyBit) paint.getPaintOptionsAndroid().flatten(buffer);
michael@0 2623 #endif
michael@0 2624 }
michael@0 2625
michael@0 2626 void SkPaint::FlatteningTraits::Unflatten(SkReadBuffer& buffer, SkPaint* paint) {
michael@0 2627 const uint32_t dirty = buffer.readUInt();
michael@0 2628 if (dirty == 0) {
michael@0 2629 return;
michael@0 2630 }
michael@0 2631 #define F(field, reader) if (dirty & k##field##_DirtyBit) paint->set##field(buffer.reader())
michael@0 2632 // Same function, except it unrefs the object newly set on the paint:
michael@0 2633 #define F_UNREF(field, reader) \
michael@0 2634 if (dirty & k##field##_DirtyBit) \
michael@0 2635 paint->set##field(buffer.reader())->unref()
michael@0 2636
michael@0 2637 F(Color, readUInt);
michael@0 2638 F(Bitfields, readUInt);
michael@0 2639 F(TextSize, readScalar);
michael@0 2640 F(TextScaleX, readScalar);
michael@0 2641 F(TextSkewX, readScalar);
michael@0 2642 F(StrokeWidth, readScalar);
michael@0 2643 F(StrokeMiter, readScalar);
michael@0 2644 F_UNREF(PathEffect, readPathEffect);
michael@0 2645 F_UNREF(Shader, readShader);
michael@0 2646 F_UNREF(Xfermode, readXfermode);
michael@0 2647 F_UNREF(MaskFilter, readMaskFilter);
michael@0 2648 F_UNREF(ColorFilter, readColorFilter);
michael@0 2649 F_UNREF(Rasterizer, readRasterizer);
michael@0 2650 F_UNREF(Looper, readDrawLooper);
michael@0 2651 F_UNREF(ImageFilter, readImageFilter);
michael@0 2652 F(Typeface, readTypeface);
michael@0 2653 #undef F
michael@0 2654 #undef F_UNREF
michael@0 2655 if (dirty & kAnnotation_DirtyBit) {
michael@0 2656 paint->setAnnotation(SkAnnotation::Create(buffer))->unref();
michael@0 2657 }
michael@0 2658 #ifdef SK_BUILD_FOR_ANDROID
michael@0 2659 if (dirty & kPaintOptionsAndroid_DirtyBit) {
michael@0 2660 SkPaintOptionsAndroid options;
michael@0 2661 options.unflatten(buffer);
michael@0 2662 paint->setPaintOptionsAndroid(options);
michael@0 2663 }
michael@0 2664 #endif
michael@0 2665 SkASSERT(dirty == paint->fDirtyBits);
michael@0 2666 }

mercurial