| 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 #include "SkAdvancedTypefaceMetrics.h" | 9 #include "SkAdvancedTypefaceMetrics.h" |
| 10 #include "SkBase64.h" | 10 #include "SkBase64.h" |
| 11 #include "SkColorPriv.h" | 11 #include "SkColorPriv.h" |
| 12 #include "SkData.h" | 12 #include "SkData.h" |
| 13 #include "SkDescriptor.h" | 13 #include "SkDescriptor.h" |
| 14 #include "SkFontDescriptor.h" | 14 #include "SkFontDescriptor.h" |
| 15 #include "SkFontHost.h" | 15 #include "SkFontHost.h" |
| 16 #include "SkGlyph.h" | 16 #include "SkGlyph.h" |
| 17 #include "SkMaskGamma.h" | 17 #include "SkMaskGamma.h" |
| 18 #include "SkOTUtils.h" | 18 #include "SkOTUtils.h" |
| 19 #include "SkPath.h" | 19 #include "SkPath.h" |
| 20 #include "SkStream.h" | 20 #include "SkStream.h" |
| 21 #include "SkString.h" | 21 #include "SkString.h" |
| 22 #include "SkTemplates.h" |
| 22 #include "SkThread.h" | 23 #include "SkThread.h" |
| 23 #include "SkTypeface_win.h" | 24 #include "SkTypeface_win.h" |
| 24 #include "SkTypefaceCache.h" | 25 #include "SkTypefaceCache.h" |
| 25 #include "SkUtils.h" | 26 #include "SkUtils.h" |
| 26 | 27 |
| 27 #include "SkTypes.h" | 28 #include "SkTypes.h" |
| 28 #include <tchar.h> | 29 #include <tchar.h> |
| 29 #include <usp10.h> | 30 #include <usp10.h> |
| 30 #include <objbase.h> | 31 #include <objbase.h> |
| 31 | 32 |
| 32 static void (*gEnsureLOGFONTAccessibleProc)(const LOGFONT&); | 33 static void (*gEnsureLOGFONTAccessibleProc)(const LOGFONT&); |
| 33 | 34 |
| 34 void SkTypeface_SetEnsureLOGFONTAccessibleProc(void (*proc)(const LOGFONT&)) { | 35 void SkTypeface_SetEnsureLOGFONTAccessibleProc(void (*proc)(const LOGFONT&)) { |
| 35 gEnsureLOGFONTAccessibleProc = proc; | 36 gEnsureLOGFONTAccessibleProc = proc; |
| 36 } | 37 } |
| 37 | 38 |
| 38 static void call_ensure_accessible(const LOGFONT& lf) { | 39 static void call_ensure_accessible(const LOGFONT& lf) { |
| 39 if (gEnsureLOGFONTAccessibleProc) { | 40 if (gEnsureLOGFONTAccessibleProc) { |
| 40 gEnsureLOGFONTAccessibleProc(lf); | 41 gEnsureLOGFONTAccessibleProc(lf); |
| 41 } | 42 } |
| 42 } | 43 } |
| 43 | 44 |
| 44 /////////////////////////////////////////////////////////////////////////////// | 45 /////////////////////////////////////////////////////////////////////////////// |
| 45 | 46 |
| 46 // always packed xxRRGGBB | 47 // always packed xxRRGGBB |
| 47 typedef uint32_t SkGdiRGB; | 48 typedef uint32_t SkGdiRGB; |
| 48 | 49 |
| 49 template <typename T> T* SkTAddByteOffset(T* ptr, size_t byteOffset) { | |
| 50 return (T*)((char*)ptr + byteOffset); | |
| 51 } | |
| 52 | |
| 53 // define this in your Makefile or .gyp to enforce AA requests | 50 // define this in your Makefile or .gyp to enforce AA requests |
| 54 // which GDI ignores at small sizes. This flag guarantees AA | 51 // which GDI ignores at small sizes. This flag guarantees AA |
| 55 // for rotated text, regardless of GDI's notions. | 52 // for rotated text, regardless of GDI's notions. |
| 56 //#define SK_ENFORCE_ROTATED_TEXT_AA_ON_WINDOWS | 53 //#define SK_ENFORCE_ROTATED_TEXT_AA_ON_WINDOWS |
| 57 | 54 |
| 58 // client3d has to undefine this for now | |
| 59 #define CAN_USE_LOGFONT_NAME | |
| 60 | |
| 61 static bool isLCD(const SkScalerContext::Rec& rec) { | 55 static bool isLCD(const SkScalerContext::Rec& rec) { |
| 62 return SkMask::kLCD16_Format == rec.fMaskFormat || | 56 return SkMask::kLCD16_Format == rec.fMaskFormat || |
| 63 SkMask::kLCD32_Format == rec.fMaskFormat; | 57 SkMask::kLCD32_Format == rec.fMaskFormat; |
| 64 } | 58 } |
| 65 | 59 |
| 66 static bool bothZero(SkScalar a, SkScalar b) { | 60 static bool bothZero(SkScalar a, SkScalar b) { |
| 67 return 0 == a && 0 == b; | 61 return 0 == a && 0 == b; |
| 68 } | 62 } |
| 69 | 63 |
| 70 // returns false if there is any non-90-rotation or skew | 64 // returns false if there is any non-90-rotation or skew |
| (...skipping 13 matching lines...) Expand all Loading... |
| 84 if (SkMask::kA8_Format == rec.fMaskFormat && !isAxisAligned(rec)) { | 78 if (SkMask::kA8_Format == rec.fMaskFormat && !isAxisAligned(rec)) { |
| 85 return true; | 79 return true; |
| 86 } | 80 } |
| 87 #endif | 81 #endif |
| 88 // false means allow GDI to generate the bits | 82 // false means allow GDI to generate the bits |
| 89 return false; | 83 return false; |
| 90 } | 84 } |
| 91 | 85 |
| 92 using namespace skia_advanced_typeface_metrics_utils; | 86 using namespace skia_advanced_typeface_metrics_utils; |
| 93 | 87 |
| 94 static const uint16_t BUFFERSIZE = (16384 - 32); | |
| 95 static uint8_t glyphbuf[BUFFERSIZE]; | |
| 96 | |
| 97 /** | 88 /** |
| 98 * Since LOGFONT wants its textsize as an int, and we support fractional sizes, | 89 * Since LOGFONT wants its textsize as an int, and we support fractional sizes, |
| 99 * and since we have a cache of LOGFONTs for our tyepfaces, we always set the | 90 * and since we have a cache of LOGFONTs for our tyepfaces, we always set the |
| 100 * lfHeight to a canonical size, and then we use the 2x2 matrix to achieve the | 91 * lfHeight to a canonical size, and then we use the 2x2 matrix to achieve the |
| 101 * actual requested size. | 92 * actual requested size. |
| 102 * | 93 * |
| 103 * Not critical to match the font's upem, but we want it big enough to avoid | 94 * Not critical to match the font's upem, but we want it big enough to avoid |
| 104 * precision loss for GDI calls that return ints (e.g. GetOutlineFontMetrics). | 95 * precision loss for GDI calls that return ints (e.g. GetOutlineFontMetrics). |
| 105 */ | 96 */ |
| 106 static const int gCanonicalTextSize = 2048; | 97 static const int gCanonicalTextSize = 2048; |
| (...skipping 440 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 547 }; | 538 }; |
| 548 | 539 |
| 549 static float mul2float(SkScalar a, SkScalar b) { | 540 static float mul2float(SkScalar a, SkScalar b) { |
| 550 return SkScalarToFloat(SkScalarMul(a, b)); | 541 return SkScalarToFloat(SkScalarMul(a, b)); |
| 551 } | 542 } |
| 552 | 543 |
| 553 static FIXED float2FIXED(float x) { | 544 static FIXED float2FIXED(float x) { |
| 554 return SkFixedToFIXED(SkFloatToFixed(x)); | 545 return SkFixedToFIXED(SkFloatToFixed(x)); |
| 555 } | 546 } |
| 556 | 547 |
| 557 SK_DECLARE_STATIC_MUTEX(gFTMutex); | |
| 558 | |
| 559 #define HIRES_TEXTSIZE 2048 | 548 #define HIRES_TEXTSIZE 2048 |
| 560 #define HIRES_SHIFT 11 | 549 #define HIRES_SHIFT 11 |
| 561 static inline SkFixed HiResToFixed(int value) { | 550 static inline SkFixed HiResToFixed(int value) { |
| 562 return value << (16 - HIRES_SHIFT); | 551 return value << (16 - HIRES_SHIFT); |
| 563 } | 552 } |
| 564 | 553 |
| 565 static bool needHiResMetrics(const SkScalar mat[2][2]) { | 554 static bool needHiResMetrics(const SkScalar mat[2][2]) { |
| 566 return mat[1][0] || mat[0][1]; | 555 return mat[1][0] || mat[0][1]; |
| 567 } | 556 } |
| 568 | 557 |
| (...skipping 13 matching lines...) Expand all Loading... |
| 582 } | 571 } |
| 583 } | 572 } |
| 584 | 573 |
| 585 SkScalerContext_Windows::SkScalerContext_Windows(SkTypeface* rawTypeface, | 574 SkScalerContext_Windows::SkScalerContext_Windows(SkTypeface* rawTypeface, |
| 586 const SkDescriptor* desc) | 575 const SkDescriptor* desc) |
| 587 : SkScalerContext(rawTypeface, desc) | 576 : SkScalerContext(rawTypeface, desc) |
| 588 , fDDC(0) | 577 , fDDC(0) |
| 589 , fFont(0) | 578 , fFont(0) |
| 590 , fSavefont(0) | 579 , fSavefont(0) |
| 591 , fSC(0) | 580 , fSC(0) |
| 592 , fGlyphCount(-1) { | 581 , fGlyphCount(-1) |
| 593 SkAutoMutexAcquire ac(gFTMutex); | 582 { |
| 594 | |
| 595 LogFontTypeface* typeface = reinterpret_cast<LogFontTypeface*>(rawTypeface); | 583 LogFontTypeface* typeface = reinterpret_cast<LogFontTypeface*>(rawTypeface); |
| 596 | 584 |
| 597 fDDC = ::CreateCompatibleDC(NULL); | 585 fDDC = ::CreateCompatibleDC(NULL); |
| 598 SetGraphicsMode(fDDC, GM_ADVANCED); | 586 SetGraphicsMode(fDDC, GM_ADVANCED); |
| 599 SetBkMode(fDDC, TRANSPARENT); | 587 SetBkMode(fDDC, TRANSPARENT); |
| 600 | 588 |
| 601 // Scaling by the DPI is inconsistent with how Skia draws elsewhere | 589 // Scaling by the DPI is inconsistent with how Skia draws elsewhere |
| 602 //SkScalar height = -(fRec.fTextSize * GetDeviceCaps(ddc, LOGPIXELSY) / 72); | 590 //SkScalar height = -(fRec.fTextSize * GetDeviceCaps(ddc, LOGPIXELSY) / 72); |
| 603 LOGFONT lf = typeface->fLogFont; | 591 LOGFONT lf = typeface->fLogFont; |
| 604 lf.lfHeight = -gCanonicalTextSize; | 592 lf.lfHeight = -gCanonicalTextSize; |
| (...skipping 312 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 917 * can get linear values. | 905 * can get linear values. |
| 918 * | 906 * |
| 919 * GDI grayscale appears to use a hard-coded gamma of 2.3. | 907 * GDI grayscale appears to use a hard-coded gamma of 2.3. |
| 920 * | 908 * |
| 921 * GDI grayscale appears to draw using the black and white rasterizer at four | 909 * GDI grayscale appears to draw using the black and white rasterizer at four |
| 922 * times the size and then downsamples to compute the coverage mask. As a | 910 * times the size and then downsamples to compute the coverage mask. As a |
| 923 * result there are only seventeen total grays. This lack of fidelity means | 911 * result there are only seventeen total grays. This lack of fidelity means |
| 924 * that shifting into other color spaces is imprecise. | 912 * that shifting into other color spaces is imprecise. |
| 925 */ | 913 */ |
| 926 static const uint8_t* getInverseGammaTableGDI() { | 914 static const uint8_t* getInverseGammaTableGDI() { |
| 915 // Since build_power_table is idempotent, many threads can build gTableGdi |
| 916 // simultaneously. |
| 927 static bool gInited; | 917 static bool gInited; |
| 928 static uint8_t gTableGdi[256]; | 918 static uint8_t gTableGdi[256]; |
| 929 if (!gInited) { | 919 if (gInited) { |
| 920 // Need a L/L (read) barrier (acquire not needed). If gInited is observe
d |
| 921 // true then gTableGdi is observable, but it must be requested. |
| 922 } else { |
| 930 build_power_table(gTableGdi, 2.3f); | 923 build_power_table(gTableGdi, 2.3f); |
| 924 // Need a S/S (write) barrier (release not needed) here so that this |
| 925 // write to gInited becomes observable after gTableGdi. |
| 931 gInited = true; | 926 gInited = true; |
| 932 } | 927 } |
| 933 return gTableGdi; | 928 return gTableGdi; |
| 934 } | 929 } |
| 935 | 930 |
| 936 /** | 931 /** |
| 937 * This will invert the gamma applied by GDI ClearType, so we can get linear | 932 * This will invert the gamma applied by GDI ClearType, so we can get linear |
| 938 * values. | 933 * values. |
| 939 * | 934 * |
| 940 * GDI ClearType uses SPI_GETFONTSMOOTHINGCONTRAST / 1000 as the gamma value. | 935 * GDI ClearType uses SPI_GETFONTSMOOTHINGCONTRAST / 1000 as the gamma value. |
| 941 * If this value is not specified, the default is a gamma of 1.4. | 936 * If this value is not specified, the default is a gamma of 1.4. |
| 942 */ | 937 */ |
| 943 static const uint8_t* getInverseGammaTableClearType() { | 938 static const uint8_t* getInverseGammaTableClearType() { |
| 939 // We don't expect SPI_GETFONTSMOOTHINGCONTRAST to ever change, so building |
| 940 // gTableClearType with build_power_table is effectively idempotent. |
| 944 static bool gInited; | 941 static bool gInited; |
| 945 static uint8_t gTableClearType[256]; | 942 static uint8_t gTableClearType[256]; |
| 946 if (!gInited) { | 943 if (gInited) { |
| 944 // Need a L/L (read) barrier (acquire not needed). If gInited is observe
d |
| 945 // true then gTableClearType is observable, but it must be requested. |
| 946 } else { |
| 947 UINT level = 0; | 947 UINT level = 0; |
| 948 if (!SystemParametersInfo(SPI_GETFONTSMOOTHINGCONTRAST, 0, &level, 0) ||
!level) { | 948 if (!SystemParametersInfo(SPI_GETFONTSMOOTHINGCONTRAST, 0, &level, 0) ||
!level) { |
| 949 // can't get the data, so use a default | 949 // can't get the data, so use a default |
| 950 level = 1400; | 950 level = 1400; |
| 951 } | 951 } |
| 952 build_power_table(gTableClearType, level / 1000.0f); | 952 build_power_table(gTableClearType, level / 1000.0f); |
| 953 // Need a S/S (write) barrier (release not needed) here so that this |
| 954 // write to gInited becomes observable after gTableClearType. |
| 953 gInited = true; | 955 gInited = true; |
| 954 } | 956 } |
| 955 return gTableClearType; | 957 return gTableClearType; |
| 956 } | 958 } |
| 957 | 959 |
| 958 #include "SkColorPriv.h" | 960 #include "SkColorPriv.h" |
| 959 | 961 |
| 960 //Cannot assume that the input rgb is gray due to possible setting of kGenA8From
LCD_Flag. | 962 //Cannot assume that the input rgb is gray due to possible setting of kGenA8From
LCD_Flag. |
| 961 template<bool APPLY_PREBLEND> | 963 template<bool APPLY_PREBLEND> |
| 962 static inline uint8_t rgb_to_a8(SkGdiRGB rgb, const uint8_t* table8) { | 964 static inline uint8_t rgb_to_a8(SkGdiRGB rgb, const uint8_t* table8) { |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 998 return (c + (c & 1)) & 0x00FFFFFF; | 1000 return (c + (c & 1)) & 0x00FFFFFF; |
| 999 } | 1001 } |
| 1000 | 1002 |
| 1001 static bool is_rgb_really_bw(const SkGdiRGB* src, int width, int height, int src
RB) { | 1003 static bool is_rgb_really_bw(const SkGdiRGB* src, int width, int height, int src
RB) { |
| 1002 for (int y = 0; y < height; ++y) { | 1004 for (int y = 0; y < height; ++y) { |
| 1003 for (int x = 0; x < width; ++x) { | 1005 for (int x = 0; x < width; ++x) { |
| 1004 if (is_not_black_or_white(src[x])) { | 1006 if (is_not_black_or_white(src[x])) { |
| 1005 return false; | 1007 return false; |
| 1006 } | 1008 } |
| 1007 } | 1009 } |
| 1008 src = SkTAddByteOffset(src, srcRB); | 1010 src = SkTAddOffset<const SkGdiRGB>(src, srcRB); |
| 1009 } | 1011 } |
| 1010 return true; | 1012 return true; |
| 1011 } | 1013 } |
| 1012 | 1014 |
| 1013 // gdi's bitmap is upside-down, so we reverse dst walking in Y | 1015 // gdi's bitmap is upside-down, so we reverse dst walking in Y |
| 1014 // whenever we copy it into skia's buffer | 1016 // whenever we copy it into skia's buffer |
| 1015 static void rgb_to_bw(const SkGdiRGB* SK_RESTRICT src, size_t srcRB, | 1017 static void rgb_to_bw(const SkGdiRGB* SK_RESTRICT src, size_t srcRB, |
| 1016 const SkGlyph& glyph) { | 1018 const SkGlyph& glyph) { |
| 1017 const int width = glyph.fWidth; | 1019 const int width = glyph.fWidth; |
| 1018 const size_t dstRB = (width + 7) >> 3; | 1020 const size_t dstRB = (width + 7) >> 3; |
| (...skipping 24 matching lines...) Expand all Loading... |
| 1043 } | 1045 } |
| 1044 if (bitCount > 0) { | 1046 if (bitCount > 0) { |
| 1045 unsigned byte = 0; | 1047 unsigned byte = 0; |
| 1046 unsigned mask = 0x80; | 1048 unsigned mask = 0x80; |
| 1047 for (int i = 0; i < bitCount; i++) { | 1049 for (int i = 0; i < bitCount; i++) { |
| 1048 byte |= src[i] & mask; | 1050 byte |= src[i] & mask; |
| 1049 mask >>= 1; | 1051 mask >>= 1; |
| 1050 } | 1052 } |
| 1051 dst[byteCount] = byte; | 1053 dst[byteCount] = byte; |
| 1052 } | 1054 } |
| 1053 src = SkTAddByteOffset(src, srcRB); | 1055 src = SkTAddOffset<const SkGdiRGB>(src, srcRB); |
| 1054 dst -= dstRB; | 1056 dst -= dstRB; |
| 1055 } | 1057 } |
| 1056 } | 1058 } |
| 1057 | 1059 |
| 1058 template<bool APPLY_PREBLEND> | 1060 template<bool APPLY_PREBLEND> |
| 1059 static void rgb_to_a8(const SkGdiRGB* SK_RESTRICT src, size_t srcRB, | 1061 static void rgb_to_a8(const SkGdiRGB* SK_RESTRICT src, size_t srcRB, |
| 1060 const SkGlyph& glyph, const uint8_t* table8) { | 1062 const SkGlyph& glyph, const uint8_t* table8) { |
| 1061 const size_t dstRB = glyph.rowBytes(); | 1063 const size_t dstRB = glyph.rowBytes(); |
| 1062 const int width = glyph.fWidth; | 1064 const int width = glyph.fWidth; |
| 1063 uint8_t* SK_RESTRICT dst = (uint8_t*)((char*)glyph.fImage + (glyph.fHeight -
1) * dstRB); | 1065 uint8_t* SK_RESTRICT dst = (uint8_t*)((char*)glyph.fImage + (glyph.fHeight -
1) * dstRB); |
| 1064 | 1066 |
| 1065 for (int y = 0; y < glyph.fHeight; y++) { | 1067 for (int y = 0; y < glyph.fHeight; y++) { |
| 1066 for (int i = 0; i < width; i++) { | 1068 for (int i = 0; i < width; i++) { |
| 1067 dst[i] = rgb_to_a8<APPLY_PREBLEND>(src[i], table8); | 1069 dst[i] = rgb_to_a8<APPLY_PREBLEND>(src[i], table8); |
| 1068 } | 1070 } |
| 1069 src = SkTAddByteOffset(src, srcRB); | 1071 src = SkTAddOffset<const SkGdiRGB>(src, srcRB); |
| 1070 dst -= dstRB; | 1072 dst -= dstRB; |
| 1071 } | 1073 } |
| 1072 } | 1074 } |
| 1073 | 1075 |
| 1074 template<bool APPLY_PREBLEND> | 1076 template<bool APPLY_PREBLEND> |
| 1075 static void rgb_to_lcd16(const SkGdiRGB* SK_RESTRICT src, size_t srcRB, const Sk
Glyph& glyph, | 1077 static void rgb_to_lcd16(const SkGdiRGB* SK_RESTRICT src, size_t srcRB, const Sk
Glyph& glyph, |
| 1076 const uint8_t* tableR, const uint8_t* tableG, const uin
t8_t* tableB) { | 1078 const uint8_t* tableR, const uint8_t* tableG, const uin
t8_t* tableB) { |
| 1077 const size_t dstRB = glyph.rowBytes(); | 1079 const size_t dstRB = glyph.rowBytes(); |
| 1078 const int width = glyph.fWidth; | 1080 const int width = glyph.fWidth; |
| 1079 uint16_t* SK_RESTRICT dst = (uint16_t*)((char*)glyph.fImage + (glyph.fHeight
- 1) * dstRB); | 1081 uint16_t* SK_RESTRICT dst = (uint16_t*)((char*)glyph.fImage + (glyph.fHeight
- 1) * dstRB); |
| 1080 | 1082 |
| 1081 for (int y = 0; y < glyph.fHeight; y++) { | 1083 for (int y = 0; y < glyph.fHeight; y++) { |
| 1082 for (int i = 0; i < width; i++) { | 1084 for (int i = 0; i < width; i++) { |
| 1083 dst[i] = rgb_to_lcd16<APPLY_PREBLEND>(src[i], tableR, tableG, tableB
); | 1085 dst[i] = rgb_to_lcd16<APPLY_PREBLEND>(src[i], tableR, tableG, tableB
); |
| 1084 } | 1086 } |
| 1085 src = SkTAddByteOffset(src, srcRB); | 1087 src = SkTAddOffset<const SkGdiRGB>(src, srcRB); |
| 1086 dst = (uint16_t*)((char*)dst - dstRB); | 1088 dst = (uint16_t*)((char*)dst - dstRB); |
| 1087 } | 1089 } |
| 1088 } | 1090 } |
| 1089 | 1091 |
| 1090 template<bool APPLY_PREBLEND> | 1092 template<bool APPLY_PREBLEND> |
| 1091 static void rgb_to_lcd32(const SkGdiRGB* SK_RESTRICT src, size_t srcRB, const Sk
Glyph& glyph, | 1093 static void rgb_to_lcd32(const SkGdiRGB* SK_RESTRICT src, size_t srcRB, const Sk
Glyph& glyph, |
| 1092 const uint8_t* tableR, const uint8_t* tableG, const uin
t8_t* tableB) { | 1094 const uint8_t* tableR, const uint8_t* tableG, const uin
t8_t* tableB) { |
| 1093 const size_t dstRB = glyph.rowBytes(); | 1095 const size_t dstRB = glyph.rowBytes(); |
| 1094 const int width = glyph.fWidth; | 1096 const int width = glyph.fWidth; |
| 1095 uint32_t* SK_RESTRICT dst = (uint32_t*)((char*)glyph.fImage + (glyph.fHeight
- 1) * dstRB); | 1097 uint32_t* SK_RESTRICT dst = (uint32_t*)((char*)glyph.fImage + (glyph.fHeight
- 1) * dstRB); |
| 1096 | 1098 |
| 1097 for (int y = 0; y < glyph.fHeight; y++) { | 1099 for (int y = 0; y < glyph.fHeight; y++) { |
| 1098 for (int i = 0; i < width; i++) { | 1100 for (int i = 0; i < width; i++) { |
| 1099 dst[i] = rgb_to_lcd32<APPLY_PREBLEND>(src[i], tableR, tableG, tableB
); | 1101 dst[i] = rgb_to_lcd32<APPLY_PREBLEND>(src[i], tableR, tableG, tableB
); |
| 1100 } | 1102 } |
| 1101 src = SkTAddByteOffset(src, srcRB); | 1103 src = SkTAddOffset<const SkGdiRGB>(src, srcRB); |
| 1102 dst = (uint32_t*)((char*)dst - dstRB); | 1104 dst = (uint32_t*)((char*)dst - dstRB); |
| 1103 } | 1105 } |
| 1104 } | 1106 } |
| 1105 | 1107 |
| 1106 static inline unsigned clamp255(unsigned x) { | 1108 static inline unsigned clamp255(unsigned x) { |
| 1107 SkASSERT(x <= 256); | 1109 SkASSERT(x <= 256); |
| 1108 return x - (x >> 8); | 1110 return x - (x >> 8); |
| 1109 } | 1111 } |
| 1110 | 1112 |
| 1111 void SkScalerContext_Windows::generateImage(const SkGlyph& glyph) { | 1113 void SkScalerContext_Windows::generateImage(const SkGlyph& glyph) { |
| 1112 SkAutoMutexAcquire ac(gFTMutex); | |
| 1113 SkASSERT(fDDC); | 1114 SkASSERT(fDDC); |
| 1114 | 1115 |
| 1115 const bool isBW = SkMask::kBW_Format == fRec.fMaskFormat; | 1116 const bool isBW = SkMask::kBW_Format == fRec.fMaskFormat; |
| 1116 const bool isAA = !isLCD(fRec); | 1117 const bool isAA = !isLCD(fRec); |
| 1117 | 1118 |
| 1118 size_t srcRB; | 1119 size_t srcRB; |
| 1119 const void* bits = fOffscreen.draw(glyph, isBW, &srcRB); | 1120 const void* bits = fOffscreen.draw(glyph, isBW, &srcRB); |
| 1120 if (NULL == bits) { | 1121 if (NULL == bits) { |
| 1121 LogFontTypeface::EnsureAccessible(this->getTypeface()); | 1122 LogFontTypeface::EnsureAccessible(this->getTypeface()); |
| 1122 bits = fOffscreen.draw(glyph, isBW, &srcRB); | 1123 bits = fOffscreen.draw(glyph, isBW, &srcRB); |
| (...skipping 18 matching lines...) Expand all Loading... |
| 1141 //Other code may also be applying the pre-blend, so we'd need another | 1142 //Other code may also be applying the pre-blend, so we'd need another |
| 1142 //one with this and one without. | 1143 //one with this and one without. |
| 1143 SkGdiRGB* addr = (SkGdiRGB*)bits; | 1144 SkGdiRGB* addr = (SkGdiRGB*)bits; |
| 1144 for (int y = 0; y < glyph.fHeight; ++y) { | 1145 for (int y = 0; y < glyph.fHeight; ++y) { |
| 1145 for (int x = 0; x < glyph.fWidth; ++x) { | 1146 for (int x = 0; x < glyph.fWidth; ++x) { |
| 1146 int r = (addr[x] >> 16) & 0xFF; | 1147 int r = (addr[x] >> 16) & 0xFF; |
| 1147 int g = (addr[x] >> 8) & 0xFF; | 1148 int g = (addr[x] >> 8) & 0xFF; |
| 1148 int b = (addr[x] >> 0) & 0xFF; | 1149 int b = (addr[x] >> 0) & 0xFF; |
| 1149 addr[x] = (table[r] << 16) | (table[g] << 8) | table[b]; | 1150 addr[x] = (table[r] << 16) | (table[g] << 8) | table[b]; |
| 1150 } | 1151 } |
| 1151 addr = SkTAddByteOffset(addr, srcRB); | 1152 addr = SkTAddOffset<SkGdiRGB>(addr, srcRB); |
| 1152 } | 1153 } |
| 1153 } | 1154 } |
| 1154 | 1155 |
| 1155 int width = glyph.fWidth; | 1156 int width = glyph.fWidth; |
| 1156 size_t dstRB = glyph.rowBytes(); | 1157 size_t dstRB = glyph.rowBytes(); |
| 1157 if (isBW) { | 1158 if (isBW) { |
| 1158 const uint8_t* src = (const uint8_t*)bits; | 1159 const uint8_t* src = (const uint8_t*)bits; |
| 1159 uint8_t* dst = (uint8_t*)((char*)glyph.fImage + (glyph.fHeight - 1) * ds
tRB); | 1160 uint8_t* dst = (uint8_t*)((char*)glyph.fImage + (glyph.fHeight - 1) * ds
tRB); |
| 1160 for (int y = 0; y < glyph.fHeight; y++) { | 1161 for (int y = 0; y < glyph.fHeight; y++) { |
| 1161 memcpy(dst, src, dstRB); | 1162 memcpy(dst, src, dstRB); |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1193 } else { | 1194 } else { |
| 1194 rgb_to_lcd32<false>(src, srcRB, glyph, | 1195 rgb_to_lcd32<false>(src, srcRB, glyph, |
| 1195 fPreBlend.fR, fPreBlend.fG, fPreBlend.fB
); | 1196 fPreBlend.fR, fPreBlend.fG, fPreBlend.fB
); |
| 1196 } | 1197 } |
| 1197 } | 1198 } |
| 1198 } | 1199 } |
| 1199 } | 1200 } |
| 1200 } | 1201 } |
| 1201 | 1202 |
| 1202 void SkScalerContext_Windows::generatePath(const SkGlyph& glyph, SkPath* path) { | 1203 void SkScalerContext_Windows::generatePath(const SkGlyph& glyph, SkPath* path) { |
| 1203 | |
| 1204 SkAutoMutexAcquire ac(gFTMutex); | |
| 1205 | |
| 1206 SkASSERT(&glyph && path); | 1204 SkASSERT(&glyph && path); |
| 1207 SkASSERT(fDDC); | 1205 SkASSERT(fDDC); |
| 1208 | 1206 |
| 1209 path->reset(); | 1207 path->reset(); |
| 1210 | 1208 |
| 1211 GLYPHMETRICS gm; | 1209 GLYPHMETRICS gm; |
| 1212 uint32_t total_size = GetGlyphOutlineW(fDDC, glyph.fID, GGO_NATIVE | GGO_GLY
PH_INDEX, &gm, BUFFERSIZE, glyphbuf, &fMat22); | 1210 |
| 1211 // Out of all the fonts on a typical Windows box, |
| 1212 // 25% of glyphs require more than 2KB. |
| 1213 // 1% of glyphs require more than 4KB. |
| 1214 // 0.01% of glyphs require more than 8KB. |
| 1215 // 8KB is less than 1% of the normal 1MB stack on Windows. |
| 1216 // Note that some web fonts glyphs require more than 20KB. |
| 1217 static const uint16_t BUFFERSIZE = (1 << 13); |
| 1218 SkAutoSTMalloc<BUFFERSIZE, uint8_t> glyphbuf(BUFFERSIZE); |
| 1219 |
| 1220 const UINT flags = GGO_NATIVE | GGO_GLYPH_INDEX; |
| 1221 DWORD total_size = GetGlyphOutlineW(fDDC, glyph.fID, flags, &gm, BUFFERSIZE,
glyphbuf, &fMat22); |
| 1213 if (GDI_ERROR == total_size) { | 1222 if (GDI_ERROR == total_size) { |
| 1214 LogFontTypeface::EnsureAccessible(this->getTypeface()); | 1223 // GDI_ERROR because the BUFFERSIZE was too small, or because the data w
as not accessible. |
| 1215 total_size = GetGlyphOutlineW(fDDC, glyph.fID, GGO_NATIVE | GGO_GLYPH_IN
DEX, &gm, BUFFERSIZE, glyphbuf, &fMat22); | 1224 // When the data is not accessable GetGlyphOutlineW fails rather quickly
, |
| 1225 // so just try to get the size. If that fails then ensure the data is ac
cessible. |
| 1226 total_size = GetGlyphOutlineW(fDDC, glyph.fID, flags, &gm, 0, NULL, &fMa
t22); |
| 1216 if (GDI_ERROR == total_size) { | 1227 if (GDI_ERROR == total_size) { |
| 1217 SkASSERT(false); | 1228 LogFontTypeface::EnsureAccessible(this->getTypeface()); |
| 1218 return; | 1229 total_size = GetGlyphOutlineW(fDDC, glyph.fID, flags, &gm, 0, NULL,
&fMat22); |
| 1230 if (GDI_ERROR == total_size) { |
| 1231 SkASSERT(false); |
| 1232 return; |
| 1233 } |
| 1234 } |
| 1235 |
| 1236 glyphbuf.reset(total_size); |
| 1237 |
| 1238 DWORD ret = GetGlyphOutlineW(fDDC, glyph.fID, flags, &gm, total_size, gl
yphbuf, &fMat22); |
| 1239 if (GDI_ERROR == ret) { |
| 1240 LogFontTypeface::EnsureAccessible(this->getTypeface()); |
| 1241 ret = GetGlyphOutlineW(fDDC, glyph.fID, flags, &gm, total_size, glyp
hbuf, &fMat22); |
| 1242 if (GDI_ERROR == ret) { |
| 1243 SkASSERT(false); |
| 1244 return; |
| 1245 } |
| 1219 } | 1246 } |
| 1220 } | 1247 } |
| 1221 | 1248 |
| 1222 const uint8_t* cur_glyph = glyphbuf; | 1249 const uint8_t* cur_glyph = glyphbuf; |
| 1223 const uint8_t* end_glyph = glyphbuf + total_size; | 1250 const uint8_t* end_glyph = glyphbuf + total_size; |
| 1224 | 1251 |
| 1225 while (cur_glyph < end_glyph) { | 1252 while (cur_glyph < end_glyph) { |
| 1226 const TTPOLYGONHEADER* th = (TTPOLYGONHEADER*)cur_glyph; | 1253 const TTPOLYGONHEADER* th = (TTPOLYGONHEADER*)cur_glyph; |
| 1227 | 1254 |
| 1228 const uint8_t* end_poly = cur_glyph + th->cb; | 1255 const uint8_t* end_poly = cur_glyph + th->cb; |
| (...skipping 637 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1866 return this->createFromStream(stream); | 1893 return this->createFromStream(stream); |
| 1867 } | 1894 } |
| 1868 | 1895 |
| 1869 private: | 1896 private: |
| 1870 SkTDArray<ENUMLOGFONTEX> fLogFontArray; | 1897 SkTDArray<ENUMLOGFONTEX> fLogFontArray; |
| 1871 }; | 1898 }; |
| 1872 | 1899 |
| 1873 SkFontMgr* SkFontMgr::Factory() { | 1900 SkFontMgr* SkFontMgr::Factory() { |
| 1874 return SkNEW(SkFontMgrGDI); | 1901 return SkNEW(SkFontMgrGDI); |
| 1875 } | 1902 } |
| OLD | NEW |