| Index: src/ports/SkFontHost_win.cpp
|
| ===================================================================
|
| --- src/ports/SkFontHost_win.cpp (revision 9661)
|
| +++ src/ports/SkFontHost_win.cpp (working copy)
|
| @@ -19,6 +19,7 @@
|
| #include "SkPath.h"
|
| #include "SkStream.h"
|
| #include "SkString.h"
|
| +#include "SkTemplates.h"
|
| #include "SkThread.h"
|
| #include "SkTypeface_win.h"
|
| #include "SkTypefaceCache.h"
|
| @@ -46,18 +47,11 @@
|
| // always packed xxRRGGBB
|
| typedef uint32_t SkGdiRGB;
|
|
|
| -template <typename T> T* SkTAddByteOffset(T* ptr, size_t byteOffset) {
|
| - return (T*)((char*)ptr + byteOffset);
|
| -}
|
| -
|
| // define this in your Makefile or .gyp to enforce AA requests
|
| // which GDI ignores at small sizes. This flag guarantees AA
|
| // for rotated text, regardless of GDI's notions.
|
| //#define SK_ENFORCE_ROTATED_TEXT_AA_ON_WINDOWS
|
|
|
| -// client3d has to undefine this for now
|
| -#define CAN_USE_LOGFONT_NAME
|
| -
|
| static bool isLCD(const SkScalerContext::Rec& rec) {
|
| return SkMask::kLCD16_Format == rec.fMaskFormat ||
|
| SkMask::kLCD32_Format == rec.fMaskFormat;
|
| @@ -91,9 +85,6 @@
|
|
|
| using namespace skia_advanced_typeface_metrics_utils;
|
|
|
| -static const uint16_t BUFFERSIZE = (16384 - 32);
|
| -static uint8_t glyphbuf[BUFFERSIZE];
|
| -
|
| /**
|
| * Since LOGFONT wants its textsize as an int, and we support fractional sizes,
|
| * and since we have a cache of LOGFONTs for our tyepfaces, we always set the
|
| @@ -554,8 +545,6 @@
|
| return SkFixedToFIXED(SkFloatToFixed(x));
|
| }
|
|
|
| -SK_DECLARE_STATIC_MUTEX(gFTMutex);
|
| -
|
| #define HIRES_TEXTSIZE 2048
|
| #define HIRES_SHIFT 11
|
| static inline SkFixed HiResToFixed(int value) {
|
| @@ -589,9 +578,8 @@
|
| , fFont(0)
|
| , fSavefont(0)
|
| , fSC(0)
|
| - , fGlyphCount(-1) {
|
| - SkAutoMutexAcquire ac(gFTMutex);
|
| -
|
| + , fGlyphCount(-1)
|
| +{
|
| LogFontTypeface* typeface = reinterpret_cast<LogFontTypeface*>(rawTypeface);
|
|
|
| fDDC = ::CreateCompatibleDC(NULL);
|
| @@ -924,10 +912,17 @@
|
| * that shifting into other color spaces is imprecise.
|
| */
|
| static const uint8_t* getInverseGammaTableGDI() {
|
| + // Since build_power_table is idempotent, many threads can build gTableGdi
|
| + // simultaneously.
|
| static bool gInited;
|
| static uint8_t gTableGdi[256];
|
| - if (!gInited) {
|
| + if (gInited) {
|
| + // Need a L/L (read) barrier (acquire not needed). If gInited is observed
|
| + // true then gTableGdi is observable, but it must be requested.
|
| + } else {
|
| build_power_table(gTableGdi, 2.3f);
|
| + // Need a S/S (write) barrier (release not needed) here so that this
|
| + // write to gInited becomes observable after gTableGdi.
|
| gInited = true;
|
| }
|
| return gTableGdi;
|
| @@ -941,15 +936,22 @@
|
| * If this value is not specified, the default is a gamma of 1.4.
|
| */
|
| static const uint8_t* getInverseGammaTableClearType() {
|
| + // We don't expect SPI_GETFONTSMOOTHINGCONTRAST to ever change, so building
|
| + // gTableClearType with build_power_table is effectively idempotent.
|
| static bool gInited;
|
| static uint8_t gTableClearType[256];
|
| - if (!gInited) {
|
| + if (gInited) {
|
| + // Need a L/L (read) barrier (acquire not needed). If gInited is observed
|
| + // true then gTableClearType is observable, but it must be requested.
|
| + } else {
|
| UINT level = 0;
|
| if (!SystemParametersInfo(SPI_GETFONTSMOOTHINGCONTRAST, 0, &level, 0) || !level) {
|
| // can't get the data, so use a default
|
| level = 1400;
|
| }
|
| build_power_table(gTableClearType, level / 1000.0f);
|
| + // Need a S/S (write) barrier (release not needed) here so that this
|
| + // write to gInited becomes observable after gTableClearType.
|
| gInited = true;
|
| }
|
| return gTableClearType;
|
| @@ -1005,7 +1007,7 @@
|
| return false;
|
| }
|
| }
|
| - src = SkTAddByteOffset(src, srcRB);
|
| + src = SkTAddOffset<const SkGdiRGB>(src, srcRB);
|
| }
|
| return true;
|
| }
|
| @@ -1050,7 +1052,7 @@
|
| }
|
| dst[byteCount] = byte;
|
| }
|
| - src = SkTAddByteOffset(src, srcRB);
|
| + src = SkTAddOffset<const SkGdiRGB>(src, srcRB);
|
| dst -= dstRB;
|
| }
|
| }
|
| @@ -1066,7 +1068,7 @@
|
| for (int i = 0; i < width; i++) {
|
| dst[i] = rgb_to_a8<APPLY_PREBLEND>(src[i], table8);
|
| }
|
| - src = SkTAddByteOffset(src, srcRB);
|
| + src = SkTAddOffset<const SkGdiRGB>(src, srcRB);
|
| dst -= dstRB;
|
| }
|
| }
|
| @@ -1082,7 +1084,7 @@
|
| for (int i = 0; i < width; i++) {
|
| dst[i] = rgb_to_lcd16<APPLY_PREBLEND>(src[i], tableR, tableG, tableB);
|
| }
|
| - src = SkTAddByteOffset(src, srcRB);
|
| + src = SkTAddOffset<const SkGdiRGB>(src, srcRB);
|
| dst = (uint16_t*)((char*)dst - dstRB);
|
| }
|
| }
|
| @@ -1098,7 +1100,7 @@
|
| for (int i = 0; i < width; i++) {
|
| dst[i] = rgb_to_lcd32<APPLY_PREBLEND>(src[i], tableR, tableG, tableB);
|
| }
|
| - src = SkTAddByteOffset(src, srcRB);
|
| + src = SkTAddOffset<const SkGdiRGB>(src, srcRB);
|
| dst = (uint32_t*)((char*)dst - dstRB);
|
| }
|
| }
|
| @@ -1109,7 +1111,6 @@
|
| }
|
|
|
| void SkScalerContext_Windows::generateImage(const SkGlyph& glyph) {
|
| - SkAutoMutexAcquire ac(gFTMutex);
|
| SkASSERT(fDDC);
|
|
|
| const bool isBW = SkMask::kBW_Format == fRec.fMaskFormat;
|
| @@ -1148,7 +1149,7 @@
|
| int b = (addr[x] >> 0) & 0xFF;
|
| addr[x] = (table[r] << 16) | (table[g] << 8) | table[b];
|
| }
|
| - addr = SkTAddByteOffset(addr, srcRB);
|
| + addr = SkTAddOffset<SkGdiRGB>(addr, srcRB);
|
| }
|
| }
|
|
|
| @@ -1200,23 +1201,49 @@
|
| }
|
|
|
| void SkScalerContext_Windows::generatePath(const SkGlyph& glyph, SkPath* path) {
|
| -
|
| - SkAutoMutexAcquire ac(gFTMutex);
|
| -
|
| SkASSERT(&glyph && path);
|
| SkASSERT(fDDC);
|
|
|
| path->reset();
|
|
|
| GLYPHMETRICS gm;
|
| - uint32_t total_size = GetGlyphOutlineW(fDDC, glyph.fID, GGO_NATIVE | GGO_GLYPH_INDEX, &gm, BUFFERSIZE, glyphbuf, &fMat22);
|
| +
|
| + // Out of all the fonts on a typical Windows box,
|
| + // 25% of glyphs require more than 2KB.
|
| + // 1% of glyphs require more than 4KB.
|
| + // 0.01% of glyphs require more than 8KB.
|
| + // 8KB is less than 1% of the normal 1MB stack on Windows.
|
| + // Note that some web fonts glyphs require more than 20KB.
|
| + static const uint16_t BUFFERSIZE = (1 << 13);
|
| + SkAutoSTMalloc<BUFFERSIZE, uint8_t> glyphbuf(BUFFERSIZE);
|
| +
|
| + const UINT flags = GGO_NATIVE | GGO_GLYPH_INDEX;
|
| + DWORD total_size = GetGlyphOutlineW(fDDC, glyph.fID, flags, &gm, BUFFERSIZE, glyphbuf, &fMat22);
|
| if (GDI_ERROR == total_size) {
|
| - LogFontTypeface::EnsureAccessible(this->getTypeface());
|
| - total_size = GetGlyphOutlineW(fDDC, glyph.fID, GGO_NATIVE | GGO_GLYPH_INDEX, &gm, BUFFERSIZE, glyphbuf, &fMat22);
|
| + // GDI_ERROR because the BUFFERSIZE was too small, or because the data was not accessible.
|
| + // When the data is not accessable GetGlyphOutlineW fails rather quickly,
|
| + // so just try to get the size. If that fails then ensure the data is accessible.
|
| + total_size = GetGlyphOutlineW(fDDC, glyph.fID, flags, &gm, 0, NULL, &fMat22);
|
| if (GDI_ERROR == total_size) {
|
| - SkASSERT(false);
|
| - return;
|
| + LogFontTypeface::EnsureAccessible(this->getTypeface());
|
| + total_size = GetGlyphOutlineW(fDDC, glyph.fID, flags, &gm, 0, NULL, &fMat22);
|
| + if (GDI_ERROR == total_size) {
|
| + SkASSERT(false);
|
| + return;
|
| + }
|
| }
|
| +
|
| + glyphbuf.reset(total_size);
|
| +
|
| + DWORD ret = GetGlyphOutlineW(fDDC, glyph.fID, flags, &gm, total_size, glyphbuf, &fMat22);
|
| + if (GDI_ERROR == ret) {
|
| + LogFontTypeface::EnsureAccessible(this->getTypeface());
|
| + ret = GetGlyphOutlineW(fDDC, glyph.fID, flags, &gm, total_size, glyphbuf, &fMat22);
|
| + if (GDI_ERROR == ret) {
|
| + SkASSERT(false);
|
| + return;
|
| + }
|
| + }
|
| }
|
|
|
| const uint8_t* cur_glyph = glyphbuf;
|
|
|