| OLD | NEW |
| 1 | 1 |
| 2 /* | 2 /* |
| 3 * Copyright 2006 The Android Open Source Project | 3 * Copyright 2006 The Android Open Source Project |
| 4 * | 4 * |
| 5 * Use of this source code is governed by a BSD-style license that can be | 5 * Use of this source code is governed by a BSD-style license that can be |
| 6 * found in the LICENSE file. | 6 * found in the LICENSE file. |
| 7 */ | 7 */ |
| 8 | 8 |
| 9 | 9 |
| 10 #include "SkScalerContext.h" | 10 #include "SkScalerContext.h" |
| (...skipping 322 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 333 SkIRect ir; | 333 SkIRect ir; |
| 334 devPath.getBounds().roundOut(&ir); | 334 devPath.getBounds().roundOut(&ir); |
| 335 | 335 |
| 336 if (ir.isEmpty() || !ir.is16Bit()) { | 336 if (ir.isEmpty() || !ir.is16Bit()) { |
| 337 goto SK_ERROR; | 337 goto SK_ERROR; |
| 338 } | 338 } |
| 339 glyph->fLeft = ir.fLeft; | 339 glyph->fLeft = ir.fLeft; |
| 340 glyph->fTop = ir.fTop; | 340 glyph->fTop = ir.fTop; |
| 341 glyph->fWidth = SkToU16(ir.width()); | 341 glyph->fWidth = SkToU16(ir.width()); |
| 342 glyph->fHeight = SkToU16(ir.height()); | 342 glyph->fHeight = SkToU16(ir.height()); |
| 343 |
| 344 if (glyph->fWidth > 0) { |
| 345 switch (fRec.fMaskFormat) { |
| 346 case SkMask::kLCD16_Format: |
| 347 case SkMask::kLCD32_Format: |
| 348 glyph->fWidth += 2; |
| 349 glyph->fLeft -= 1; |
| 350 break; |
| 351 default: |
| 352 break; |
| 353 } |
| 354 } |
| 343 } | 355 } |
| 344 } | 356 } |
| 345 | 357 |
| 346 if (SkMask::kARGB32_Format != glyph->fMaskFormat) { | 358 if (SkMask::kARGB32_Format != glyph->fMaskFormat) { |
| 347 glyph->fMaskFormat = fRec.fMaskFormat; | 359 glyph->fMaskFormat = fRec.fMaskFormat; |
| 348 } | 360 } |
| 349 | 361 |
| 350 // If we are going to create the mask, then we cannot keep the color | 362 // If we are going to create the mask, then we cannot keep the color |
| 351 if ((fGenerateImageFromPath || fMaskFilter) && | 363 if ((fGenerateImageFromPath || fMaskFilter) && |
| 352 SkMask::kARGB32_Format == glyph->fMaskFormat) { | 364 SkMask::kARGB32_Format == glyph->fMaskFormat) { |
| (...skipping 26 matching lines...) Expand all Loading... |
| 379 // draw nothing 'cause we failed | 391 // draw nothing 'cause we failed |
| 380 glyph->fLeft = 0; | 392 glyph->fLeft = 0; |
| 381 glyph->fTop = 0; | 393 glyph->fTop = 0; |
| 382 glyph->fWidth = 0; | 394 glyph->fWidth = 0; |
| 383 glyph->fHeight = 0; | 395 glyph->fHeight = 0; |
| 384 // put a valid value here, in case it was earlier set to | 396 // put a valid value here, in case it was earlier set to |
| 385 // MASK_FORMAT_JUST_ADVANCE | 397 // MASK_FORMAT_JUST_ADVANCE |
| 386 glyph->fMaskFormat = fRec.fMaskFormat; | 398 glyph->fMaskFormat = fRec.fMaskFormat; |
| 387 } | 399 } |
| 388 | 400 |
| 401 #define SK_SHOW_TEXT_BLIT_COVERAGE 0 |
| 389 | 402 |
| 390 static void applyLUTToA8Mask(const SkMask& mask, const uint8_t* lut) { | 403 static void applyLUTToA8Mask(const SkMask& mask, const uint8_t* lut) { |
| 391 uint8_t* SK_RESTRICT dst = (uint8_t*)mask.fImage; | 404 uint8_t* SK_RESTRICT dst = (uint8_t*)mask.fImage; |
| 392 unsigned rowBytes = mask.fRowBytes; | 405 unsigned rowBytes = mask.fRowBytes; |
| 393 | 406 |
| 394 for (int y = mask.fBounds.height() - 1; y >= 0; --y) { | 407 for (int y = mask.fBounds.height() - 1; y >= 0; --y) { |
| 395 for (int x = mask.fBounds.width() - 1; x >= 0; --x) { | 408 for (int x = mask.fBounds.width() - 1; x >= 0; --x) { |
| 396 dst[x] = lut[dst[x]]; | 409 dst[x] = lut[dst[x]]; |
| 397 } | 410 } |
| 398 dst += rowBytes; | 411 dst += rowBytes; |
| 399 } | 412 } |
| 400 } | 413 } |
| 401 | 414 |
| 402 template<bool APPLY_PREBLEND> | 415 template<bool APPLY_PREBLEND> |
| 403 static void pack3xHToLCD16(const SkBitmap& src, const SkMask& dst, | 416 static void pack4xHToLCD16(const SkBitmap& src, const SkMask& dst, |
| 404 const SkMaskGamma::PreBlend& maskPreBlend) { | 417 const SkMaskGamma::PreBlend& maskPreBlend) { |
| 418 #define SAMPLES_PER_PIXEL 4 |
| 419 #define LCD_PER_PIXEL 3 |
| 405 SkASSERT(SkBitmap::kA8_Config == src.config()); | 420 SkASSERT(SkBitmap::kA8_Config == src.config()); |
| 406 SkASSERT(SkMask::kLCD16_Format == dst.fFormat); | 421 SkASSERT(SkMask::kLCD16_Format == dst.fFormat); |
| 407 | 422 |
| 408 const int width = dst.fBounds.width(); | 423 const int sample_width = src.width(); |
| 409 const int height = dst.fBounds.height(); | 424 const int height = src.height(); |
| 425 |
| 410 uint16_t* dstP = (uint16_t*)dst.fImage; | 426 uint16_t* dstP = (uint16_t*)dst.fImage; |
| 411 size_t dstRB = dst.fRowBytes; | 427 size_t dstRB = dst.fRowBytes; |
| 428 // An N tap FIR is defined by |
| 429 // out[n] = coeff[0]*x[n] + coeff[1]*x[n-1] + ... + coeff[N]*x[n-N] |
| 430 // or |
| 431 // out[n] = sum(i, 0, N, coeff[i]*x[n-i]) |
| 432 |
| 433 // The strategy is to use one FIR (different coefficients) for each of r, g,
and b. |
| 434 // This means using every 4th FIR output value of each FIR and discarding th
e rest. |
| 435 // The FIRs are aligned, and the coefficients reach 5 samples to each side o
f their 'center'. |
| 436 // (For r and b this is technically incorrect, but the coeffs outside round
to zero anyway.) |
| 437 |
| 438 // These are in some fixed point repesentation. |
| 439 // Adding up to more than one simulates ink spread. |
| 440 // For implementation reasons, these should never add up to more than two. |
| 441 |
| 442 // Coefficients determined by a gausian where 5 samples = 3 std deviations (
0x110 'contrast'). |
| 443 // Calculated using tools/generate_fir_coeff.py |
| 444 // With this one almost no fringing is ever seen, but it is imperceptibly bl
urry. |
| 445 // The lcd smoothed text is almost imperceptibly different from gray, |
| 446 // but is still sharper on small stems and small rounded corners than gray. |
| 447 // This also seems to be about as wide as one can get and only have a three
pixel kernel. |
| 448 // TODO: caculate these at runtime so parameters can be adjusted (esp contra
st). |
| 449 static const unsigned int coefficients[LCD_PER_PIXEL][SAMPLES_PER_PIXEL*3] =
{ |
| 450 //The red subpixel is centered inside the first sample (at 1/6 pixel), a
nd is shifted. |
| 451 { 0x03, 0x0b, 0x1c, 0x33, 0x40, 0x39, 0x24, 0x10, 0x05, 0x01, 0x00, 0x
00, }, |
| 452 //The green subpixel is centered between two samples (at 1/2 pixel), so
is symetric |
| 453 { 0x00, 0x02, 0x08, 0x16, 0x2b, 0x3d, 0x3d, 0x2b, 0x16, 0x08, 0x02, 0x
00, }, |
| 454 //The blue subpixel is centered inside the last sample (at 5/6 pixel), a
nd is shifted. |
| 455 { 0x00, 0x00, 0x01, 0x05, 0x10, 0x24, 0x39, 0x40, 0x33, 0x1c, 0x0b, 0x
03, }, |
| 456 }; |
| 412 | 457 |
| 413 for (int y = 0; y < height; ++y) { | 458 for (int y = 0; y < height; ++y) { |
| 414 const uint8_t* srcP = src.getAddr8(0, y); | 459 const uint8_t* srcP = src.getAddr8(0, y); |
| 415 for (int x = 0; x < width; ++x) { | 460 |
| 416 U8CPU r = sk_apply_lut_if<APPLY_PREBLEND>(*srcP++, maskPreBlend.fR); | 461 // TODO: this fir filter implementation is straight forward, but slow. |
| 417 U8CPU g = sk_apply_lut_if<APPLY_PREBLEND>(*srcP++, maskPreBlend.fG); | 462 // It should be possible to make it much faster. |
| 418 U8CPU b = sk_apply_lut_if<APPLY_PREBLEND>(*srcP++, maskPreBlend.fB); | 463 for (int sample_x = -4, pixel_x = 0; sample_x < sample_width + 4; sample
_x += 4, ++pixel_x) { |
| 419 dstP[x] = SkPack888ToRGB16(r, g, b); | 464 int fir[LCD_PER_PIXEL] = { 0 }; |
| 465 for (int sample_index = SkMax32(0, sample_x - 4), coeff_index = samp
le_index - (sample_x - 4) |
| 466 ; sample_index < SkMin32(sample_x + 8, sample_width) |
| 467 ; ++sample_index, ++coeff_index) |
| 468 { |
| 469 int sample_value = srcP[sample_index]; |
| 470 for (int subpxl_index = 0; subpxl_index < LCD_PER_PIXEL; ++subpx
l_index) { |
| 471 fir[subpxl_index] += coefficients[subpxl_index][coeff_index]
* sample_value; |
| 472 } |
| 473 } |
| 474 for (int subpxl_index = 0; subpxl_index < LCD_PER_PIXEL; ++subpxl_in
dex) { |
| 475 fir[subpxl_index] /= 0x100; |
| 476 fir[subpxl_index] = SkMin32(fir[subpxl_index], 255); |
| 477 } |
| 478 |
| 479 U8CPU r = sk_apply_lut_if<APPLY_PREBLEND>(fir[0], maskPreBlend.fR); |
| 480 U8CPU g = sk_apply_lut_if<APPLY_PREBLEND>(fir[1], maskPreBlend.fG); |
| 481 U8CPU b = sk_apply_lut_if<APPLY_PREBLEND>(fir[2], maskPreBlend.fB); |
| 482 #if SK_SHOW_TEXT_BLIT_COVERAGE |
| 483 r = SkMax32(r, 10); g = SkMax32(g, 10); b = SkMax32(b, 10); |
| 484 #endif |
| 485 dstP[pixel_x] = SkPack888ToRGB16(r, g, b); |
| 420 } | 486 } |
| 421 dstP = (uint16_t*)((char*)dstP + dstRB); | 487 dstP = (uint16_t*)((char*)dstP + dstRB); |
| 422 } | 488 } |
| 423 } | 489 } |
| 424 | 490 |
| 425 template<bool APPLY_PREBLEND> | 491 template<bool APPLY_PREBLEND> |
| 426 static void pack3xHToLCD32(const SkBitmap& src, const SkMask& dst, | 492 static void pack4xHToLCD32(const SkBitmap& src, const SkMask& dst, |
| 427 const SkMaskGamma::PreBlend& maskPreBlend) { | 493 const SkMaskGamma::PreBlend& maskPreBlend) { |
| 428 SkASSERT(SkBitmap::kA8_Config == src.config()); | 494 SkASSERT(SkBitmap::kA8_Config == src.config()); |
| 429 SkASSERT(SkMask::kLCD32_Format == dst.fFormat); | 495 SkASSERT(SkMask::kLCD32_Format == dst.fFormat); |
| 430 | 496 |
| 431 const int width = dst.fBounds.width(); | 497 const int width = dst.fBounds.width(); |
| 432 const int height = dst.fBounds.height(); | 498 const int height = dst.fBounds.height(); |
| 433 SkPMColor* dstP = (SkPMColor*)dst.fImage; | 499 SkPMColor* dstP = (SkPMColor*)dst.fImage; |
| 434 size_t dstRB = dst.fRowBytes; | 500 size_t dstRB = dst.fRowBytes; |
| 435 | 501 |
| 436 for (int y = 0; y < height; ++y) { | 502 for (int y = 0; y < height; ++y) { |
| 437 const uint8_t* srcP = src.getAddr8(0, y); | 503 const uint8_t* srcP = src.getAddr8(0, y); |
| 504 |
| 505 // TODO: need to use fir filter here as well. |
| 438 for (int x = 0; x < width; ++x) { | 506 for (int x = 0; x < width; ++x) { |
| 439 U8CPU r = sk_apply_lut_if<APPLY_PREBLEND>(*srcP++, maskPreBlend.fR); | 507 U8CPU r = sk_apply_lut_if<APPLY_PREBLEND>(*srcP++, maskPreBlend.fR); |
| 440 U8CPU g = sk_apply_lut_if<APPLY_PREBLEND>(*srcP++, maskPreBlend.fG); | 508 U8CPU g = sk_apply_lut_if<APPLY_PREBLEND>(*srcP++, maskPreBlend.fG); |
| 441 U8CPU b = sk_apply_lut_if<APPLY_PREBLEND>(*srcP++, maskPreBlend.fB); | 509 U8CPU b = sk_apply_lut_if<APPLY_PREBLEND>(*srcP++, maskPreBlend.fB); |
| 442 dstP[x] = SkPackARGB32(0xFF, r, g, b); | 510 dstP[x] = SkPackARGB32(0xFF, r, g, b); |
| 443 } | 511 } |
| 444 dstP = (SkPMColor*)((char*)dstP + dstRB); | 512 dstP = (SkPMColor*)((char*)dstP + dstRB); |
| 445 } | 513 } |
| 446 } | 514 } |
| 447 | 515 |
| (...skipping 17 matching lines...) Expand all Loading... |
| 465 paint.setAntiAlias(false); | 533 paint.setAntiAlias(false); |
| 466 } else { | 534 } else { |
| 467 config = SkBitmap::kA8_Config; | 535 config = SkBitmap::kA8_Config; |
| 468 paint.setAntiAlias(true); | 536 paint.setAntiAlias(true); |
| 469 switch (mask.fFormat) { | 537 switch (mask.fFormat) { |
| 470 case SkMask::kA8_Format: | 538 case SkMask::kA8_Format: |
| 471 break; | 539 break; |
| 472 case SkMask::kLCD16_Format: | 540 case SkMask::kLCD16_Format: |
| 473 case SkMask::kLCD32_Format: | 541 case SkMask::kLCD32_Format: |
| 474 // TODO: trigger off LCD orientation | 542 // TODO: trigger off LCD orientation |
| 475 dstW *= 3; | 543 dstW = 4*dstW - 8; |
| 476 matrix.postScale(SkIntToScalar(3), SK_Scalar1); | 544 matrix.setTranslate(-SkIntToScalar(mask.fBounds.fLeft + 1), |
| 545 -SkIntToScalar(mask.fBounds.fTop)); |
| 546 matrix.postScale(SkIntToScalar(4), SK_Scalar1); |
| 477 dstRB = 0; // signals we need a copy | 547 dstRB = 0; // signals we need a copy |
| 478 break; | 548 break; |
| 479 default: | 549 default: |
| 480 SkDEBUGFAIL("unexpected mask format"); | 550 SkDEBUGFAIL("unexpected mask format"); |
| 481 } | 551 } |
| 482 } | 552 } |
| 483 | 553 |
| 484 SkRasterClip clip; | 554 SkRasterClip clip; |
| 485 clip.setRect(SkIRect::MakeWH(dstW, dstH)); | 555 clip.setRect(SkIRect::MakeWH(dstW, dstH)); |
| 486 | 556 |
| (...skipping 20 matching lines...) Expand all Loading... |
| 507 draw.drawPath(path, paint); | 577 draw.drawPath(path, paint); |
| 508 | 578 |
| 509 switch (mask.fFormat) { | 579 switch (mask.fFormat) { |
| 510 case SkMask::kA8_Format: | 580 case SkMask::kA8_Format: |
| 511 if (maskPreBlend.isApplicable()) { | 581 if (maskPreBlend.isApplicable()) { |
| 512 applyLUTToA8Mask(mask, maskPreBlend.fG); | 582 applyLUTToA8Mask(mask, maskPreBlend.fG); |
| 513 } | 583 } |
| 514 break; | 584 break; |
| 515 case SkMask::kLCD16_Format: | 585 case SkMask::kLCD16_Format: |
| 516 if (maskPreBlend.isApplicable()) { | 586 if (maskPreBlend.isApplicable()) { |
| 517 pack3xHToLCD16<true>(bm, mask, maskPreBlend); | 587 pack4xHToLCD16<true>(bm, mask, maskPreBlend); |
| 518 } else { | 588 } else { |
| 519 pack3xHToLCD16<false>(bm, mask, maskPreBlend); | 589 pack4xHToLCD16<false>(bm, mask, maskPreBlend); |
| 520 } | 590 } |
| 521 break; | 591 break; |
| 522 case SkMask::kLCD32_Format: | 592 case SkMask::kLCD32_Format: |
| 523 if (maskPreBlend.isApplicable()) { | 593 if (maskPreBlend.isApplicable()) { |
| 524 pack3xHToLCD32<true>(bm, mask, maskPreBlend); | 594 pack4xHToLCD32<true>(bm, mask, maskPreBlend); |
| 525 } else { | 595 } else { |
| 526 pack3xHToLCD32<false>(bm, mask, maskPreBlend); | 596 pack4xHToLCD32<false>(bm, mask, maskPreBlend); |
| 527 } | 597 } |
| 528 break; | 598 break; |
| 529 default: | 599 default: |
| 530 break; | 600 break; |
| 531 } | 601 } |
| 532 } | 602 } |
| 533 | 603 |
| 534 static void extract_alpha(const SkMask& dst, | 604 static void extract_alpha(const SkMask& dst, |
| 535 const SkPMColor* srcRow, size_t srcRB) { | 605 const SkPMColor* srcRow, size_t srcRB) { |
| 536 int width = dst.fBounds.width(); | 606 int width = dst.fBounds.width(); |
| (...skipping 318 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 855 SkScalerContext* SkTypeface::createScalerContext(const SkDescriptor* desc, | 925 SkScalerContext* SkTypeface::createScalerContext(const SkDescriptor* desc, |
| 856 bool allowFailure) const { | 926 bool allowFailure) const { |
| 857 SkScalerContext* c = this->onCreateScalerContext(desc); | 927 SkScalerContext* c = this->onCreateScalerContext(desc); |
| 858 | 928 |
| 859 if (!c && !allowFailure) { | 929 if (!c && !allowFailure) { |
| 860 c = SkNEW_ARGS(SkScalerContext_Empty, | 930 c = SkNEW_ARGS(SkScalerContext_Empty, |
| 861 (const_cast<SkTypeface*>(this), desc)); | 931 (const_cast<SkTypeface*>(this), desc)); |
| 862 } | 932 } |
| 863 return c; | 933 return c; |
| 864 } | 934 } |
| OLD | NEW |