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 |