diff options
author | brettw@google.com <brettw@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-12-12 21:01:41 +0000 |
---|---|---|
committer | brettw@google.com <brettw@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-12-12 21:01:41 +0000 |
commit | 52e935d04c59135739c3a68fb6e19d313dc6d5ad (patch) | |
tree | 95f7ab178b045bef4456cbf92c6aa7e476becd99 /skia/ports | |
parent | 30fab79877b4bb067944b74d98346ac9bb6bfc7e (diff) | |
download | chromium_src-52e935d04c59135739c3a68fb6e19d313dc6d5ad.zip chromium_src-52e935d04c59135739c3a68fb6e19d313dc6d5ad.tar.gz chromium_src-52e935d04c59135739c3a68fb6e19d313dc6d5ad.tar.bz2 |
New drop of Skia. This is up to CL 121320.
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@6925 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'skia/ports')
23 files changed, 2134 insertions, 555 deletions
diff --git a/skia/ports/SkFontHost_FONTPATH.cpp b/skia/ports/SkFontHost_FONTPATH.cpp index 94f068c..3cbccaf 100644 --- a/skia/ports/SkFontHost_FONTPATH.cpp +++ b/skia/ports/SkFontHost_FONTPATH.cpp @@ -1,6 +1,6 @@ /* libs/graphics/ports/SkFontHost_android.cpp ** -** Copyright 2006, Google Inc. +** Copyright 2006, The Android Open Source Project ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. diff --git a/skia/ports/SkFontHost_FreeType.cpp b/skia/ports/SkFontHost_FreeType.cpp index 5a18d51..3ad4a65 100644 --- a/skia/ports/SkFontHost_FreeType.cpp +++ b/skia/ports/SkFontHost_FreeType.cpp @@ -1,17 +1,17 @@ /* libs/graphics/ports/SkFontHost_FreeType.cpp ** -** Copyright 2006, Google Inc. +** Copyright 2006, The Android Open Source Project ** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You may obtain a copy of the License at +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at ** -** http://www.apache.org/licenses/LICENSE-2.0 +** http://www.apache.org/licenses/LICENSE-2.0 ** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and ** limitations under the License. */ @@ -32,8 +32,11 @@ #include FT_OUTLINE_H #include FT_SIZES_H #include FT_TRUETYPE_TABLES_H +#ifdef FT_ADVANCES_H +#include FT_ADVANCES_H +#endif -//#define ENABLE_GLYPH_SPEW // for tracing calls to generateMetrics/generateImage +//#define ENABLE_GLYPH_SPEW // for tracing calls //#define DUMP_STRIKE_CREATION #ifdef SK_DEBUG @@ -69,7 +72,8 @@ protected: virtual void generateMetrics(SkGlyph* glyph); virtual void generateImage(const SkGlyph& glyph); virtual void generatePath(const SkGlyph& glyph, SkPath* path); - virtual void generateFontMetrics(SkPaint::FontMetrics* mx, SkPaint::FontMetrics* my); + virtual void generateFontMetrics(SkPaint::FontMetrics* mx, + SkPaint::FontMetrics* my); private: SkFaceRec* fFaceRec; @@ -95,9 +99,8 @@ struct SkFaceRec { uint32_t fRefCnt; uint32_t fFontID; - SkFaceRec(SkStream* strm, uint32_t fontID); - ~SkFaceRec() - { + SkFaceRec(SkStream* strm, uint32_t fontID); + ~SkFaceRec() { SkFontHost::CloseStream(fFontID, fSkStream); } }; @@ -106,21 +109,15 @@ extern "C" { static unsigned long sk_stream_read(FT_Stream stream, unsigned long offset, unsigned char* buffer, - unsigned long count ) - { + unsigned long count ) { SkStream* str = (SkStream*)stream->descriptor.pointer; - if (count) - { - if (!str->rewind()) - { + if (count) { + if (!str->rewind()) { return 0; - } - else - { + } else { unsigned long ret; - if (offset) - { + if (offset) { ret = str->read(NULL, offset); if (ret != offset) { return 0; @@ -136,30 +133,24 @@ extern "C" { return count; } - static void sk_stream_close( FT_Stream stream) - { - } + static void sk_stream_close( FT_Stream stream) {} } SkFaceRec::SkFaceRec(SkStream* strm, uint32_t fontID) - : fSkStream(strm), fFontID(fontID) -{ + : fSkStream(strm), fFontID(fontID) { // SkDEBUGF(("SkFaceRec: opening %s (%p)\n", key.c_str(), strm)); - memset(&fFTStream, 0, sizeof(fFTStream)); - fFTStream.size = fSkStream->read(NULL, 0); // find out how big the stream is + bzero(&fFTStream, sizeof(fFTStream)); + fFTStream.size = fSkStream->getLength(); fFTStream.descriptor.pointer = fSkStream; fFTStream.read = sk_stream_read; fFTStream.close = sk_stream_close; } -static SkFaceRec* ref_ft_face(uint32_t fontID) -{ +static SkFaceRec* ref_ft_face(uint32_t fontID) { SkFaceRec* rec = gFaceRecHead; - while (rec) - { - if (rec->fFontID == fontID) - { + while (rec) { + if (rec->fFontID == fontID) { SkASSERT(rec->fFace); rec->fRefCnt += 1; return rec; @@ -168,8 +159,7 @@ static SkFaceRec* ref_ft_face(uint32_t fontID) } SkStream* strm = SkFontHost::OpenStream(fontID); - if (NULL == strm) - { + if (NULL == strm) { SkDEBUGF(("SkFontHost::OpenStream failed opening %x\n", fontID)); sk_throw(); return 0; @@ -182,15 +172,12 @@ static SkFaceRec* ref_ft_face(uint32_t fontID) memset(&args, 0, sizeof(args)); const void* memoryBase = strm->getMemoryBase(); - if (NULL != memoryBase) - { + if (NULL != memoryBase) { //printf("mmap(%s)\n", keyString.c_str()); args.flags = FT_OPEN_MEMORY; args.memory_base = (const FT_Byte*)memoryBase; args.memory_size = strm->getLength(); - } - else - { + } else { //printf("fopen(%s)\n", keyString.c_str()); args.flags = FT_OPEN_STREAM; args.stream = &rec->fFTStream; @@ -198,15 +185,12 @@ static SkFaceRec* ref_ft_face(uint32_t fontID) FT_Error err = FT_Open_Face(gFTLibrary, &args, 0, &rec->fFace); - if (err) // bad filename, try the default font - { + if (err) { // bad filename, try the default font fprintf(stderr, "ERROR: unable to open font '%x'\n", fontID); SkDELETE(rec); sk_throw(); return 0; - } - else - { + } else { SkASSERT(rec->fFace); //fprintf(stderr, "Opened font '%s'\n", filename.c_str()); rec->fNext = gFaceRecHead; @@ -216,22 +200,18 @@ static SkFaceRec* ref_ft_face(uint32_t fontID) } } -static void unref_ft_face(FT_Face face) -{ +static void unref_ft_face(FT_Face face) { SkFaceRec* rec = gFaceRecHead; SkFaceRec* prev = NULL; - while (rec) - { + while (rec) { SkFaceRec* next = rec->fNext; - if (rec->fFace == face) - { - if (--rec->fRefCnt == 0) - { - if (prev) + if (rec->fFace == face) { + if (--rec->fRefCnt == 0) { + if (prev) { prev->fNext = next; - else + } else { gFaceRecHead = next; - + } FT_Done_Face(face); SkDELETE(rec); } @@ -246,14 +226,12 @@ static void unref_ft_face(FT_Face face) /////////////////////////////////////////////////////////////////////////// SkScalerContext_FreeType::SkScalerContext_FreeType(const SkDescriptor* desc) - : SkScalerContext(desc), fFTSize(NULL) -{ + : SkScalerContext(desc), fFTSize(NULL) { SkAutoMutexAcquire ac(gFTMutex); FT_Error err; - if (gFTCount == 0) - { + if (gFTCount == 0) { err = FT_Init_FreeType(&gFTLibrary); // SkDEBUGF(("FT_Init_FreeType returned %d\n", err)); SkASSERT(err == 0); @@ -261,10 +239,8 @@ SkScalerContext_FreeType::SkScalerContext_FreeType(const SkDescriptor* desc) ++gFTCount; // load the font file - { - fFaceRec = ref_ft_face(fRec.fFontID); - fFace = fFaceRec ? fFaceRec->fFace : NULL; - } + fFaceRec = ref_ft_face(fRec.fFontID); + fFace = fFaceRec ? fFaceRec->fFace : NULL; // compute our factors from the record @@ -286,8 +262,8 @@ SkScalerContext_FreeType::SkScalerContext_FreeType(const SkDescriptor* desc) SkScalar sx = m.getScaleX(); SkScalar sy = m.getScaleY(); - if (m.getSkewX() || m.getSkewY() || sx < 0 || sy < 0) // sort of give up on hinting - { + if (m.getSkewX() || m.getSkewY() || sx < 0 || sy < 0) { + // sort of give up on hinting sx = SkMaxScalar(SkScalarAbs(sx), SkScalarAbs(m.getSkewX())); sy = SkMaxScalar(SkScalarAbs(m.getSkewY()), SkScalarAbs(sy)); sx = sy = SkScalarAve(sx, sy); @@ -299,9 +275,7 @@ SkScalerContext_FreeType::SkScalerContext_FreeType(const SkDescriptor* desc) fMatrix22.xy = -SkScalarToFixed(SkScalarMul(m.getSkewX(), inv)); fMatrix22.yx = -SkScalarToFixed(SkScalarMul(m.getSkewY(), inv)); fMatrix22.yy = SkScalarToFixed(SkScalarMul(m.getScaleY(), inv)); - } - else - { + } else { fMatrix22.xx = fMatrix22.yy = SK_Fixed1; fMatrix22.xy = fMatrix22.yx = 0; } @@ -315,19 +289,14 @@ SkScalerContext_FreeType::SkScalerContext_FreeType(const SkDescriptor* desc) uint32_t render_flags = FT_LOAD_TARGET_NORMAL; // we force autohinting at the moment - // (no patent rights to apple's stuff) switch (fRec.fHints) { case kNo_Hints: flags |= FT_LOAD_NO_HINTING; break; case kSubpixel_Hints: -#if 1 // this is clearer (vertically), but ~2x slower flags |= FT_LOAD_FORCE_AUTOHINT; render_flags = FT_LOAD_TARGET_LIGHT; -#else - flags |= FT_LOAD_NO_HINTING; -#endif break; case kNormal_Hints: // Uncommenting the following line disables the font's hinting @@ -335,8 +304,14 @@ SkScalerContext_FreeType::SkScalerContext_FreeType(const SkDescriptor* desc) // generate baselines that look at little like Firefox. It's // expected that Mike Reed will rework this code sometime soon so // we don't wish to make more extensive changes. - - // flags |= FT_LOAD_FORCE_AUTOHINT; + //flags |= FT_LOAD_FORCE_AUTOHINT; +#ifdef ANDROID + /* Switch to light hinting (vertical only) to address some chars + that behaved poorly with NORMAL. In the future we could consider + making this choice exposed at runtime to the caller. + */ + render_flags = FT_LOAD_TARGET_LIGHT; +#endif break; } @@ -382,18 +357,17 @@ SkScalerContext_FreeType::SkScalerContext_FreeType(const SkDescriptor* desc) } } -SkScalerContext_FreeType::~SkScalerContext_FreeType() -{ - if (fFTSize != NULL) +SkScalerContext_FreeType::~SkScalerContext_FreeType() { + if (fFTSize != NULL) { FT_Done_Size(fFTSize); + } SkAutoMutexAcquire ac(gFTMutex); - if (fFace != NULL) + if (fFace != NULL) { unref_ft_face(fFace); - - if (--gFTCount == 0) - { + } + if (--gFTCount == 0) { // SkDEBUGF(("FT_Done_FreeType\n")); FT_Done_FreeType(gFTLibrary); SkDEBUGCODE(gFTLibrary = NULL;) @@ -403,8 +377,7 @@ SkScalerContext_FreeType::~SkScalerContext_FreeType() /* We call this before each use of the fFace, since we may be sharing this face with other context (at different sizes). */ -FT_Error SkScalerContext_FreeType::setupSize() -{ +FT_Error SkScalerContext_FreeType::setupSize() { if (SkFontHost::ResolveTypeface(fRec.fFontID) == NULL) { return (FT_Error)-1; } @@ -415,9 +388,7 @@ FT_Error SkScalerContext_FreeType::setupSize() SkDEBUGF(("SkScalerContext_FreeType::FT_Activate_Size(%x, 0x%x, 0x%x) returned 0x%x\n", fFaceRec->fFontID, fScaleX, fScaleY, err)); fFTSize = NULL; - } - else - { + } else { // seems we need to reset this every time (not sure why, but without it // I get random italics from some other fFTSize) FT_Set_Transform( fFace, &fMatrix22, NULL); @@ -425,49 +396,71 @@ FT_Error SkScalerContext_FreeType::setupSize() return err; } -unsigned SkScalerContext_FreeType::generateGlyphCount() const -{ +unsigned SkScalerContext_FreeType::generateGlyphCount() const { return fFace->num_glyphs; } -uint16_t SkScalerContext_FreeType::generateCharToGlyph(SkUnichar uni) -{ +uint16_t SkScalerContext_FreeType::generateCharToGlyph(SkUnichar uni) { return SkToU16(FT_Get_Char_Index( fFace, uni )); } -static FT_Pixel_Mode compute_pixel_mode(SkMask::Format format) -{ +static FT_Pixel_Mode compute_pixel_mode(SkMask::Format format) { switch (format) { - case SkMask::kBW_Format: - return FT_PIXEL_MODE_MONO; - case SkMask::kLCD_Format: - return FT_PIXEL_MODE_LCD; - case SkMask::kA8_Format: - default: - return FT_PIXEL_MODE_GRAY; + case SkMask::kBW_Format: + return FT_PIXEL_MODE_MONO; + case SkMask::kLCD_Format: + return FT_PIXEL_MODE_LCD; + case SkMask::kA8_Format: + default: + return FT_PIXEL_MODE_GRAY; } } -void SkScalerContext_FreeType::generateAdvance(SkGlyph* glyph) -{ - // insert new freetype API when it is available -#if 1 - this->generateMetrics(glyph); -#else - // hack - SkAutoMutexAcquire ac(gFTMutex); - +static void set_glyph_metrics_on_error(SkGlyph* glyph) { glyph->fRsbDelta = 0; glyph->fLsbDelta = 0; - - glyph->fAdvanceX = fScaleX * 2 / 3; + glyph->fWidth = 0; + glyph->fHeight = 0; + glyph->fTop = 0; + glyph->fLeft = 0; + glyph->fAdvanceX = 0; glyph->fAdvanceY = 0; -#endif +} + +void SkScalerContext_FreeType::generateAdvance(SkGlyph* glyph) { +#ifdef FT_ADVANCES_H + /* unhinted and light hinted text have linearly scaled advances + * which are very cheap to compute with some font formats... + */ + { + SkAutoMutexAcquire ac(gFTMutex); + + if (this->setupSize()) { + set_glyph_metrics_on_error(glyph); + return; + } + + FT_Error error; + FT_Fixed advance; + + error = FT_Get_Advance( fFace, glyph->getGlyphID(fBaseGlyphCount), + fLoadGlyphFlags | FT_ADVANCE_FLAG_FAST_ONLY, + &advance ); + if (0 == error) { + glyph->fRsbDelta = 0; + glyph->fLsbDelta = 0; + glyph->fAdvanceX = advance; // advance *2/3; //DEBUG + glyph->fAdvanceY = 0; + return; + } + } +#endif /* FT_ADVANCES_H */ + /* otherwise, we need to load/hint the glyph, which is slower */ + this->generateMetrics(glyph); return; } -void SkScalerContext_FreeType::generateMetrics(SkGlyph* glyph) -{ +void SkScalerContext_FreeType::generateMetrics(SkGlyph* glyph) { SkAutoMutexAcquire ac(gFTMutex); glyph->fRsbDelta = 0; @@ -475,41 +468,35 @@ void SkScalerContext_FreeType::generateMetrics(SkGlyph* glyph) FT_Error err; - if (this->setupSize()) + if (this->setupSize()) { goto ERROR; + } err = FT_Load_Glyph( fFace, glyph->getGlyphID(fBaseGlyphCount), fLoadGlyphFlags ); - if (err != 0) - { + if (err != 0) { SkDEBUGF(("SkScalerContext_FreeType::generateMetrics(%x): FT_Load_Glyph(glyph:%d flags:%d) returned 0x%x\n", fFaceRec->fFontID, glyph->getGlyphID(fBaseGlyphCount), fLoadGlyphFlags, err)); ERROR: - glyph->fWidth = 0; - glyph->fHeight = 0; - glyph->fTop = 0; - glyph->fLeft = 0; - glyph->fAdvanceX = 0; - glyph->fAdvanceY = 0; + set_glyph_metrics_on_error(glyph); return; } - - switch ( fFace->glyph->format ) - { + + switch ( fFace->glyph->format ) { case FT_GLYPH_FORMAT_OUTLINE: FT_BBox bbox; - + FT_Outline_Get_CBox(&fFace->glyph->outline, &bbox); - if (kSubpixel_Hints == fRec.fHints) - { + if (kSubpixel_Hints == fRec.fHints) { int dx = glyph->getSubXFixed() >> 10; int dy = glyph->getSubYFixed() >> 10; + // negate dy since freetype-y-goes-up and skia-y-goes-down bbox.xMin += dx; - bbox.yMin += dy; + bbox.yMin -= dy; bbox.xMax += dx; - bbox.yMax += dy; + bbox.yMax -= dy; } - + bbox.xMin &= ~63; bbox.yMin &= ~63; bbox.xMax = (bbox.xMax + 63) & ~63; @@ -520,7 +507,7 @@ void SkScalerContext_FreeType::generateMetrics(SkGlyph* glyph) glyph->fTop = -SkToS16(bbox.yMax >> 6); glyph->fLeft = SkToS16(bbox.xMin >> 6); break; - + case FT_GLYPH_FORMAT_BITMAP: glyph->fWidth = SkToU16(fFace->glyph->bitmap.width); glyph->fHeight = SkToU16(fFace->glyph->bitmap.rows); @@ -530,21 +517,17 @@ void SkScalerContext_FreeType::generateMetrics(SkGlyph* glyph) default: SkASSERT(!"unknown glyph format"); - goto ERROR; + goto ERROR; } - - if (kNormal_Hints == fRec.fHints) - { + + if (kNormal_Hints == fRec.fHints) { glyph->fAdvanceX = SkFDot6ToFixed(fFace->glyph->advance.x); glyph->fAdvanceY = -SkFDot6ToFixed(fFace->glyph->advance.y); - if (fRec.fFlags & kDevKernText_Flag) - { + if (fRec.fFlags & kDevKernText_Flag) { glyph->fRsbDelta = SkToS8(fFace->glyph->rsb_delta); glyph->fLsbDelta = SkToS8(fFace->glyph->lsb_delta); } - } - else - { + } else { glyph->fAdvanceX = SkFixedMul(fMatrix22.xx, fFace->glyph->linearHoriAdvance); glyph->fAdvanceY = -SkFixedMul(fMatrix22.yx, fFace->glyph->linearHoriAdvance); } @@ -555,14 +538,14 @@ void SkScalerContext_FreeType::generateMetrics(SkGlyph* glyph) #endif } -void SkScalerContext_FreeType::generateImage(const SkGlyph& glyph) -{ +void SkScalerContext_FreeType::generateImage(const SkGlyph& glyph) { SkAutoMutexAcquire ac(gFTMutex); FT_Error err; - if (this->setupSize()) + if (this->setupSize()) { goto ERROR; + } err = FT_Load_Glyph( fFace, glyph.getGlyphID(fBaseGlyphCount), fLoadGlyphFlags); if (err != 0) { @@ -574,17 +557,17 @@ void SkScalerContext_FreeType::generateImage(const SkGlyph& glyph) } switch ( fFace->glyph->format ) { - case FT_GLYPH_FORMAT_OUTLINE: - { + case FT_GLYPH_FORMAT_OUTLINE: { FT_Outline* outline = &fFace->glyph->outline; FT_BBox bbox; FT_Bitmap target; int dx = 0, dy = 0; - if (kSubpixel_Hints == fRec.fHints) - { + if (kSubpixel_Hints == fRec.fHints) { dx = glyph.getSubXFixed() >> 10; dy = glyph.getSubYFixed() >> 10; + // negate dy since freetype-y-goes-up and skia-y-goes-down + dy = -dy; } FT_Outline_Get_CBox(outline, &bbox); /* @@ -602,21 +585,20 @@ void SkScalerContext_FreeType::generateImage(const SkGlyph& glyph) target.rows = glyph.fHeight; target.pitch = glyph.rowBytes(); target.buffer = reinterpret_cast<uint8_t*>(glyph.fImage); - target.pixel_mode = compute_pixel_mode((SkMask::Format)fRec.fMaskFormat); + target.pixel_mode = compute_pixel_mode( + (SkMask::Format)fRec.fMaskFormat); target.num_grays = 256; - + memset(glyph.fImage, 0, glyph.rowBytes() * glyph.fHeight); FT_Outline_Get_Bitmap(gFTLibrary, outline, &target); - } - break; - - case FT_GLYPH_FORMAT_BITMAP: - SkASSERT_CONTINUE(glyph.fWidth == fFace->glyph->bitmap.width); - SkASSERT_CONTINUE(glyph.fHeight == fFace->glyph->bitmap.rows); - SkASSERT_CONTINUE(glyph.fTop == -fFace->glyph->bitmap_top); - SkASSERT_CONTINUE(glyph.fLeft == fFace->glyph->bitmap_left); - - { + } break; + + case FT_GLYPH_FORMAT_BITMAP: { + SkASSERT_CONTINUE(glyph.fWidth == fFace->glyph->bitmap.width); + SkASSERT_CONTINUE(glyph.fHeight == fFace->glyph->bitmap.rows); + SkASSERT_CONTINUE(glyph.fTop == -fFace->glyph->bitmap_top); + SkASSERT_CONTINUE(glyph.fLeft == fFace->glyph->bitmap_left); + const uint8_t* src = (const uint8_t*)fFace->glyph->bitmap.buffer; uint8_t* dst = (uint8_t*)glyph.fImage; unsigned srcRowBytes = fFace->glyph->bitmap.pitch; @@ -624,23 +606,21 @@ void SkScalerContext_FreeType::generateImage(const SkGlyph& glyph) unsigned minRowBytes = SkMin32(srcRowBytes, dstRowBytes); unsigned extraRowBytes = dstRowBytes - minRowBytes; - for (int y = fFace->glyph->bitmap.rows - 1; y >= 0; --y) - { + for (int y = fFace->glyph->bitmap.rows - 1; y >= 0; --y) { memcpy(dst, src, minRowBytes); memset(dst + minRowBytes, 0, extraRowBytes); src += srcRowBytes; dst += dstRowBytes; } - } - break; - + } break; + default: SkASSERT(!"unknown glyph format"); goto ERROR; } } -/////////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// #define ft2sk(x) SkFixedToScalar((x) << 10) @@ -650,37 +630,36 @@ void SkScalerContext_FreeType::generateImage(const SkGlyph& glyph) #define CONST_PARAM #endif -static int move_proc(CONST_PARAM FT_Vector* pt, void* ctx) -{ +static int move_proc(CONST_PARAM FT_Vector* pt, void* ctx) { SkPath* path = (SkPath*)ctx; path->close(); // to close the previous contour (if any) path->moveTo(ft2sk(pt->x), -ft2sk(pt->y)); return 0; } -static int line_proc(CONST_PARAM FT_Vector* pt, void* ctx) -{ +static int line_proc(CONST_PARAM FT_Vector* pt, void* ctx) { SkPath* path = (SkPath*)ctx; path->lineTo(ft2sk(pt->x), -ft2sk(pt->y)); return 0; } -static int quad_proc(CONST_PARAM FT_Vector* pt0, CONST_PARAM FT_Vector* pt1, void* ctx) -{ +static int quad_proc(CONST_PARAM FT_Vector* pt0, CONST_PARAM FT_Vector* pt1, + void* ctx) { SkPath* path = (SkPath*)ctx; path->quadTo(ft2sk(pt0->x), -ft2sk(pt0->y), ft2sk(pt1->x), -ft2sk(pt1->y)); return 0; } -static int cubic_proc(CONST_PARAM FT_Vector* pt0, CONST_PARAM FT_Vector* pt1, CONST_PARAM FT_Vector* pt2, void* ctx) -{ +static int cubic_proc(CONST_PARAM FT_Vector* pt0, CONST_PARAM FT_Vector* pt1, + CONST_PARAM FT_Vector* pt2, void* ctx) { SkPath* path = (SkPath*)ctx; - path->cubicTo(ft2sk(pt0->x), -ft2sk(pt0->y), ft2sk(pt1->x), -ft2sk(pt1->y), ft2sk(pt2->x), -ft2sk(pt2->y)); + path->cubicTo(ft2sk(pt0->x), -ft2sk(pt0->y), ft2sk(pt1->x), + -ft2sk(pt1->y), ft2sk(pt2->x), -ft2sk(pt2->y)); return 0; } -void SkScalerContext_FreeType::generatePath(const SkGlyph& glyph, SkPath* path) -{ +void SkScalerContext_FreeType::generatePath(const SkGlyph& glyph, + SkPath* path) { SkAutoMutexAcquire ac(gFTMutex); SkASSERT(&glyph && path); @@ -769,19 +748,21 @@ SkFontHost_VDMX_Parse(int* ymax, int* ymin, return result; } -void SkScalerContext_FreeType::generateFontMetrics(SkPaint::FontMetrics* mx, SkPaint::FontMetrics* my) -{ - if (NULL == mx && NULL == my) +void SkScalerContext_FreeType::generateFontMetrics(SkPaint::FontMetrics* mx, + SkPaint::FontMetrics* my) { + if (NULL == mx && NULL == my) { return; + } SkAutoMutexAcquire ac(gFTMutex); - if (this->setupSize()) - { - if (mx) - memset(mx, 0, sizeof(SkPaint::FontMetrics)); - if (my) - memset(my, 0, sizeof(SkPaint::FontMetrics)); + if (this->setupSize()) { + if (mx) { + bzero(mx, sizeof(SkPaint::FontMetrics)); + } + if (my) { + bzero(my, sizeof(SkPaint::FontMetrics)); + } return; } @@ -795,8 +776,9 @@ void SkScalerContext_FreeType::generateFontMetrics(SkPaint::FontMetrics* mx, SkP SkScalar xrange = static_cast<SkScalar>(face->bbox.xMax - face->bbox.xMin) / upem; int leading = face->height - face->ascender + face->descender; - if (leading < 0) + if (leading < 0) { leading = 0; + } // Try to get the OS/2 table from the font. This contains the specific // average font width metrics which Windows uses. @@ -827,16 +809,14 @@ void SkScalerContext_FreeType::generateFontMetrics(SkPaint::FontMetrics* mx, SkP } // convert upem-y values into scalar points - for (int i = 0; i < 7; i++) - { + for (int i = 0; i < 7; i++) { SkFixed y = SkMulDiv(scaleY, ys[i], upem); SkFixed x = SkFixedMul(mxy, y); y = SkFixedMul(myy, y); pts[i].set(SkFixedToScalar(x), SkFixedToScalar(y)); } - if (mx) - { + if (mx) { mx->fTop = pts[0].fX; mx->fAscent = pts[1].fX; mx->fDescent = pts[2].fX; @@ -851,8 +831,7 @@ void SkScalerContext_FreeType::generateFontMetrics(SkPaint::FontMetrics* mx, SkP // I believe my->fVDMXMetricsValid = false; } - if (my) - { + if (my) { my->fTop = pts[0].fY; my->fAscent = pts[1].fY; my->fDescent = pts[2].fY; @@ -878,8 +857,7 @@ void SkScalerContext_FreeType::generateFontMetrics(SkPaint::FontMetrics* mx, SkP //////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////// -SkScalerContext* SkFontHost::CreateScalerContext(const SkDescriptor* desc) -{ +SkScalerContext* SkFontHost::CreateScalerContext(const SkDescriptor* desc) { return SkNEW_ARGS(SkScalerContext_FreeType, (desc)); } @@ -888,20 +866,19 @@ SkScalerContext* SkFontHost::CreateScalerContext(const SkDescriptor* desc) /* Export this so that other parts of our FonttHost port can make use of our ability to extract the name+style from a stream, using FreeType's api. */ -SkTypeface::Style find_name_and_style(SkStream* stream, SkString* name) -{ +SkTypeface::Style find_name_and_style(SkStream* stream, SkString* name) { FT_Library library; if (FT_Init_FreeType(&library)) { name->set(NULL); return SkTypeface::kNormal; } - + FT_Open_Args args; memset(&args, 0, sizeof(args)); - + const void* memoryBase = stream->getMemoryBase(); FT_StreamRec streamRec; - + if (NULL != memoryBase) { args.flags = FT_OPEN_MEMORY; args.memory_base = (const FT_Byte*)memoryBase; @@ -912,28 +889,28 @@ SkTypeface::Style find_name_and_style(SkStream* stream, SkString* name) streamRec.descriptor.pointer = stream; streamRec.read = sk_stream_read; streamRec.close = sk_stream_close; - + args.flags = FT_OPEN_STREAM; args.stream = &streamRec; } - + FT_Face face; if (FT_Open_Face(library, &args, 0, &face)) { FT_Done_FreeType(library); name->set(NULL); return SkTypeface::kNormal; } - + name->set(face->family_name); int style = SkTypeface::kNormal; - + if (face->style_flags & FT_STYLE_FLAG_BOLD) { style |= SkTypeface::kBold; - } + } if (face->style_flags & FT_STYLE_FLAG_ITALIC) { style |= SkTypeface::kItalic; } - + FT_Done_Face(face); FT_Done_FreeType(library); return (SkTypeface::Style)style; diff --git a/skia/ports/SkFontHost_android.cpp b/skia/ports/SkFontHost_android.cpp index d7613c6..665c788 100644 --- a/skia/ports/SkFontHost_android.cpp +++ b/skia/ports/SkFontHost_android.cpp @@ -1,6 +1,6 @@ /* libs/graphics/ports/SkFontHost_android.cpp ** -** Copyright 2006, Google Inc. +** Copyright 2006, The Android Open Source Project ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. @@ -276,6 +276,7 @@ public: virtual SkStream* openStream() = 0; virtual void closeStream(SkStream*) = 0; + virtual const char* getUniqueString() const = 0; private: bool fIsSysFont; @@ -301,7 +302,8 @@ public: // overrides virtual SkStream* openStream() { return fStream; } virtual void closeStream(SkStream*) {} - + virtual const char* getUniqueString() const { return NULL; } + private: SkStream* fStream; @@ -344,7 +346,14 @@ public: { SkDELETE(stream); } - + virtual const char* getUniqueString() const { + const char* str = strrchr(fPath.c_str(), '/'); + if (str) { + str += 1; // skip the '/' + } + return str; + } + private: SkString fPath; @@ -387,8 +396,8 @@ static const char* gSansNames[] = { }; static const char* gSerifNames[] = { - "serif", "times", "times new roman", "palatino", "goudy", - "fantasy", "cursive", NULL + "serif", "times", "times new roman", "palatino", "georgia", "baskerville", + "goudy", "fantasy", "cursive", "ITC Stone Serif", NULL }; static const char* gMonoNames[] = { @@ -479,6 +488,51 @@ static void load_system_fonts() /////////////////////////////////////////////////////////////////////////////// +void SkFontHost::Serialize(const SkTypeface* face, SkWStream* stream) { + const char* name = ((FamilyTypeface*)face)->getUniqueString(); + + stream->write8((uint8_t)face->getStyle()); + + if (NULL == name || 0 == *name) { + stream->writePackedUInt(0); +// SkDebugf("--- fonthost serialize null\n"); + } else { + uint32_t len = strlen(name); + stream->writePackedUInt(len); + stream->write(name, len); +// SkDebugf("--- fonthost serialize <%s> %d\n", name, face->getStyle()); + } +} + +SkTypeface* SkFontHost::Deserialize(SkStream* stream) { + load_system_fonts(); + + int style = stream->readU8(); + + int len = stream->readPackedUInt(); + if (len > 0) { + SkString str; + str.resize(len); + stream->read(str.writable_str(), len); + + const FontInitRec* rec = gSystemFonts; + for (size_t i = 0; i < SK_ARRAY_COUNT(gSystemFonts); i++) { + if (strcmp(rec[i].fFileName, str.c_str()) == 0) { + // backup until we hit the fNames + for (int j = i; j >= 0; --j) { + if (rec[j].fNames != NULL) { + return SkFontHost::FindTypeface(NULL, rec[j].fNames[0], + (SkTypeface::Style)style); + } + } + } + } + } + return SkFontHost::FindTypeface(NULL, NULL, (SkTypeface::Style)style); +} + +/////////////////////////////////////////////////////////////////////////////// + SkTypeface* SkFontHost::FindTypeface(const SkTypeface* familyFace, const char familyName[], SkTypeface::Style style) @@ -495,6 +549,7 @@ SkTypeface* SkFontHost::FindTypeface(const SkTypeface* familyFace, if (NULL != familyFace) { tf = find_typeface(familyFace, style); } else if (NULL != familyName) { +// SkDebugf("======= familyName <%s>\n", familyName); tf = find_typeface(familyName, style); } diff --git a/skia/ports/SkFontHost_gamma.cpp b/skia/ports/SkFontHost_gamma.cpp index 28c7051..0b95bce 100644 --- a/skia/ports/SkFontHost_gamma.cpp +++ b/skia/ports/SkFontHost_gamma.cpp @@ -1,42 +1,95 @@ - #include "SkFontHost.h" #include <math.h> +// define this to use pre-compiled tables for gamma. This is slightly faster, +// and doesn't create any RW global memory, but means we cannot change the +// gamma at runtime. +#define USE_PREDEFINED_GAMMA_TABLES + +#ifndef USE_PREDEFINED_GAMMA_TABLES + // define this if you want to spew out the "C" code for the tables, given + // the current values for SK_BLACK_GAMMA and SK_WHITE_GAMMA. + #define DUMP_GAMMA_TABLESx +#endif + +/////////////////////////////////////////////////////////////////////////////// + +#ifdef USE_PREDEFINED_GAMMA_TABLES + +#include "sk_predefined_gamma.h" + +#else // use writable globals for gamma tables + +static bool gGammaIsBuilt; +static uint8_t gBlackGamma[256], gWhiteGamma[256]; + +#define SK_BLACK_GAMMA (1.4f) +#define SK_WHITE_GAMMA (1/1.4f) + static void build_power_table(uint8_t table[], float ee) { -// printf("------ build_power_table %g\n", ee); + // printf("------ build_power_table %g\n", ee); for (int i = 0; i < 256; i++) { float x = i / 255.f; - // printf(" %d %g", i, x); + // printf(" %d %g", i, x); x = powf(x, ee); - // printf(" %g", x); + // printf(" %g", x); int xx = SkScalarRound(SkFloatToScalar(x * 255)); - // printf(" %d\n", xx); + // printf(" %d\n", xx); table[i] = SkToU8(xx); } } -static bool gGammaIsBuilt; -static uint8_t gBlackGamma[256], gWhiteGamma[256]; +#ifdef DUMP_GAMMA_TABLES + +#include "SkString.h" -#define ANDROID_BLACK_GAMMA (1.4f) -#define ANDROID_WHITE_GAMMA (1/1.4f) +static void dump_a_table(const char name[], const uint8_t table[], + float gamma) { + SkDebugf("\n"); + SkDebugf("\/\/ Gamma table for %g\n", gamma); + SkDebugf("static const uint8_t %s[] = {\n", name); + for (int y = 0; y < 16; y++) { + SkString line, tmp; + for (int x = 0; x < 16; x++) { + tmp.printf("0x%02X, ", *table++); + line.append(tmp); + } + SkDebugf(" %s\n", line.c_str()); + } + SkDebugf("};\n"); +} + +#endif + +#endif + +/////////////////////////////////////////////////////////////////////////////// void SkFontHost::GetGammaTables(const uint8_t* tables[2]) { - // would be cleaner if these tables were precomputed and just linked in +#ifndef USE_PREDEFINED_GAMMA_TABLES if (!gGammaIsBuilt) { - build_power_table(gBlackGamma, ANDROID_BLACK_GAMMA); - build_power_table(gWhiteGamma, ANDROID_WHITE_GAMMA); + build_power_table(gBlackGamma, SK_BLACK_GAMMA); + build_power_table(gWhiteGamma, SK_WHITE_GAMMA); gGammaIsBuilt = true; + +#ifdef DUMP_GAMMA_TABLES + dump_a_table("gBlackGamma", gBlackGamma, SK_BLACK_GAMMA); + dump_a_table("gWhiteGamma", gWhiteGamma, SK_WHITE_GAMMA); +#endif } +#endif tables[0] = gBlackGamma; tables[1] = gWhiteGamma; } +// If the luminance is <= this value, then apply the black gamma table #define BLACK_GAMMA_THRESHOLD 0x40 + +// If the luminance is >= this value, then apply the white gamma table #define WHITE_GAMMA_THRESHOLD 0xC0 int SkFontHost::ComputeGammaFlag(const SkPaint& paint) diff --git a/skia/ports/SkFontHost_linux.cpp b/skia/ports/SkFontHost_linux.cpp new file mode 100644 index 0000000..f75718d --- /dev/null +++ b/skia/ports/SkFontHost_linux.cpp @@ -0,0 +1,604 @@ +/* libs/graphics/ports/SkFontHost_android.cpp + ** + ** Copyright 2006, The Android Open Source Project + ** + ** Licensed under the Apache License, Version 2.0 (the "License"); + ** you may not use this file except in compliance with the License. + ** You may obtain a copy of the License at + ** + ** http://www.apache.org/licenses/LICENSE-2.0 + ** + ** Unless required by applicable law or agreed to in writing, software + ** distributed under the License is distributed on an "AS IS" BASIS, + ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ** See the License for the specific language governing permissions and + ** limitations under the License. + */ + +#include "SkFontHost.h" +#include "SkDescriptor.h" +#include "SkMMapStream.h" +#include "SkOSFile.h" +#include "SkPaint.h" +#include "SkString.h" +#include "SkStream.h" +#include "SkThread.h" +#include "SkTSearch.h" +#include <stdio.h> + +#define FONT_CACHE_MEMORY_BUDGET (1 * 1024 * 1024) + +#ifndef SK_FONT_FILE_PREFIX + #define SK_FONT_FILE_PREFIX "/usr/share/fonts/truetype/msttcorefonts/" +#endif + +SkTypeface::Style find_name_and_style(SkStream* stream, SkString* name); + +static void GetFullPathForSysFonts(SkString* full, const char name[]) +{ + full->append(SK_FONT_FILE_PREFIX); + full->append(name); +} + +/////////////////////////////////////////////////////////////////////////////// + +struct FamilyRec; + +/* This guy holds a mapping of a name -> family, used for looking up fonts. + Since it is stored in a stretchy array that doesn't preserve object + semantics, we don't use constructor/destructors, but just have explicit + helpers to manage our internal bookkeeping. + */ +struct NameFamilyPair { + const char* fName; // we own this + FamilyRec* fFamily; // we don't own this, we just reference it + + void construct(const char name[], FamilyRec* family) + { + fName = strdup(name); + fFamily = family; // we don't own this, so just record the referene + } + void destruct() + { + free((char*)fName); + // we don't own family, so just ignore our reference + } +}; + +// we use atomic_inc to grow this for each typeface we create +static int32_t gUniqueFontID; + +// this is the mutex that protects these globals +static SkMutex gFamilyMutex; +static FamilyRec* gFamilyHead; +static SkTDArray<NameFamilyPair> gNameList; + +struct FamilyRec { + FamilyRec* fNext; + SkTypeface* fFaces[4]; + + FamilyRec() + { + fNext = gFamilyHead; + memset(fFaces, 0, sizeof(fFaces)); + gFamilyHead = this; + } +}; + +static SkTypeface* find_best_face(const FamilyRec* family, + SkTypeface::Style style) +{ + SkTypeface* const* faces = family->fFaces; + + if (faces[style] != NULL) { // exact match + return faces[style]; + } + // look for a matching bold + style = (SkTypeface::Style)(style ^ SkTypeface::kItalic); + if (faces[style] != NULL) { + return faces[style]; + } + // look for the plain + if (faces[SkTypeface::kNormal] != NULL) { + return faces[SkTypeface::kNormal]; + } + // look for anything + for (int i = 0; i < 4; i++) { + if (faces[i] != NULL) { + return faces[i]; + } + } + // should never get here, since the faces list should not be empty + SkASSERT(!"faces list is empty"); + return NULL; +} + +static FamilyRec* find_family(const SkTypeface* member) +{ + FamilyRec* curr = gFamilyHead; + while (curr != NULL) { + for (int i = 0; i < 4; i++) { + if (curr->fFaces[i] == member) { + return curr; + } + } + curr = curr->fNext; + } + return NULL; +} + +static SkTypeface* resolve_uniqueID(uint32_t uniqueID) +{ + FamilyRec* curr = gFamilyHead; + while (curr != NULL) { + for (int i = 0; i < 4; i++) { + SkTypeface* face = curr->fFaces[i]; + if (face != NULL && face->uniqueID() == uniqueID) { + return face; + } + } + curr = curr->fNext; + } + return NULL; +} + +/* Remove reference to this face from its family. If the resulting family + is empty (has no faces), return that family, otherwise return NULL + */ +static FamilyRec* remove_from_family(const SkTypeface* face) +{ + FamilyRec* family = find_family(face); + SkASSERT(family->fFaces[face->style()] == face); + family->fFaces[face->style()] = NULL; + + for (int i = 0; i < 4; i++) { + if (family->fFaces[i] != NULL) { // family is non-empty + return NULL; + } + } + return family; // return the empty family +} + +// maybe we should make FamilyRec be doubly-linked +static void detach_and_delete_family(FamilyRec* family) +{ + FamilyRec* curr = gFamilyHead; + FamilyRec* prev = NULL; + + while (curr != NULL) { + FamilyRec* next = curr->fNext; + if (curr == family) { + if (prev == NULL) { + gFamilyHead = next; + } else { + prev->fNext = next; + } + SkDELETE(family); + return; + } + prev = curr; + curr = next; + } + SkASSERT(!"Yikes, couldn't find family in our list to remove/delete"); +} + +static FamilyRec* find_familyrec(const char name[]) { + const NameFamilyPair* list = gNameList.begin(); + int index = SkStrLCSearch(&list[0].fName, gNameList.count(), name, + sizeof(list[0])); + return index >= 0 ? list[index].fFamily : NULL; +} + +static SkTypeface* find_typeface(const char name[], SkTypeface::Style style) { + FamilyRec* rec = find_familyrec(name); + return rec ? find_best_face(rec, style) : NULL; +} + +static SkTypeface* find_typeface(const SkTypeface* familyMember, + SkTypeface::Style style) +{ + const FamilyRec* family = find_family(familyMember); + return family ? find_best_face(family, style) : NULL; +} + +static void add_name(const char name[], FamilyRec* family) +{ + SkAutoAsciiToLC tolc(name); + name = tolc.lc(); + + NameFamilyPair* list = gNameList.begin(); + int count = gNameList.count(); + + int index = SkStrLCSearch(&list[0].fName, count, name, sizeof(list[0])); + + if (index < 0) { + list = gNameList.insert(~index); + list->construct(name, family); + } +} + +static void remove_from_names(FamilyRec* emptyFamily) +{ +#ifdef SK_DEBUG + for (int i = 0; i < 4; i++) { + SkASSERT(emptyFamily->fFaces[i] == NULL); + } +#endif + + SkTDArray<NameFamilyPair>& list = gNameList; + + // must go backwards when removing + for (int i = list.count() - 1; i >= 0; --i) { + NameFamilyPair* pair = &list[i]; + if (pair->fFamily == emptyFamily) { + pair->destruct(); + list.remove(i); + } + } +} + +/////////////////////////////////////////////////////////////////////////////// + +class FamilyTypeface : public SkTypeface { +public: + FamilyTypeface(Style style, bool sysFont, FamilyRec* family) + : SkTypeface(style, sk_atomic_inc(&gUniqueFontID) + 1) + { + fIsSysFont = sysFont; + + SkAutoMutexAcquire ac(gFamilyMutex); + + if (NULL == family) { + family = SkNEW(FamilyRec); + } + family->fFaces[style] = this; + fFamilyRec = family; // just record it so we can return it if asked + } + + virtual ~FamilyTypeface() + { + SkAutoMutexAcquire ac(gFamilyMutex); + + // remove us from our family. If the family is now empty, we return + // that and then remove that family from the name list + FamilyRec* family = remove_from_family(this); + if (NULL != family) { + remove_from_names(family); + detach_and_delete_family(family); + } + } + + bool isSysFont() const { return fIsSysFont; } + FamilyRec* getFamily() const { return fFamilyRec; } + + virtual SkStream* openStream() = 0; + virtual void closeStream(SkStream*) = 0; + virtual const char* getUniqueString() const = 0; + +private: + FamilyRec* fFamilyRec; // we don't own this, just point to it + bool fIsSysFont; + + typedef SkTypeface INHERITED; +}; + +/////////////////////////////////////////////////////////////////////////////// + +class StreamTypeface : public FamilyTypeface { +public: + StreamTypeface(Style style, bool sysFont, FamilyRec* family, + SkStream* stream) + : INHERITED(style, sysFont, family) + { + fStream = stream; + } + virtual ~StreamTypeface() + { + SkDELETE(fStream); + } + + // overrides + virtual SkStream* openStream() { return fStream; } + virtual void closeStream(SkStream*) {} + virtual const char* getUniqueString() const { return NULL; } + +private: + SkStream* fStream; + + typedef FamilyTypeface INHERITED; +}; + +class FileTypeface : public FamilyTypeface { +public: + FileTypeface(Style style, bool sysFont, FamilyRec* family, + const char path[]) + : INHERITED(style, sysFont, family) { + fPath.set(path); + } + + // overrides + virtual SkStream* openStream() + { + SkStream* stream = SkNEW_ARGS(SkMMAPStream, (fPath.c_str())); + + // check for failure + if (stream->getLength() <= 0) { + SkDELETE(stream); + // maybe MMAP isn't supported. try FILE + stream = SkNEW_ARGS(SkFILEStream, (fPath.c_str())); + if (stream->getLength() <= 0) { + SkDELETE(stream); + stream = NULL; + } + } + return stream; + } + virtual void closeStream(SkStream* stream) + { + SkDELETE(stream); + } + virtual const char* getUniqueString() const { + const char* str = strrchr(fPath.c_str(), '/'); + if (str) { + str += 1; // skip the '/' + } + return str; + } + +private: + SkString fPath; + + typedef FamilyTypeface INHERITED; +}; + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// + +static bool get_name_and_style(const char path[], SkString* name, + SkTypeface::Style* style) +{ + SkMMAPStream stream(path); + if (stream.getLength() > 0) { + *style = find_name_and_style(&stream, name); + return true; + } + else { + SkFILEStream stream(path); + if (stream.getLength() > 0) { + *style = find_name_and_style(&stream, name); + return true; + } + } + + SkDebugf("---- failed to open <%s> as a font\n", path); + return false; +} + +// these globals are assigned (once) by load_system_fonts() +static SkTypeface* gFallBackTypeface; +static FamilyRec* gDefaultFamily; +static SkTypeface* gDefaultNormal; + +static void load_system_fonts() +{ + // check if we've already be called + if (NULL != gDefaultNormal) { + return; + } + + SkOSFile::Iter iter(SK_FONT_FILE_PREFIX, ".ttf"); + SkString name; + + while (iter.next(&name, false)) { + SkString filename; + GetFullPathForSysFonts(&filename, name.c_str()); +// while (filename.size() == 0) { filename.set("/usr/share/fonts/truetype/msttcorefonts/Arial.ttf"); + + SkString realname; + SkTypeface::Style style; + + if (!get_name_and_style(filename.c_str(), &realname, &style)) { + SkDebugf("------ can't load <%s> as a font\n", filename.c_str()); + continue; + } + +// SkDebugf("font: <%s> %d <%s>\n", realname.c_str(), style, filename.c_str()); + + FamilyRec* family = find_familyrec(realname.c_str()); + // this constructor puts us into the global gFamilyHead llist + FamilyTypeface* tf = SkNEW_ARGS(FileTypeface, + (style, + true, // system-font (cannot delete) + family, // what family to join + filename.c_str()) // filename + ); + + if (NULL == family) { + add_name(realname.c_str(), tf->getFamily()); + } + } + + // do this after all fonts are loaded. This is our default font, and it + // acts as a sentinel so we only execute load_system_fonts() once + static const char* gDefaultNames[] = { + "Arial", "Verdana", "Times New Roman", NULL + }; + const char** names = gDefaultNames; + while (*names) { + SkTypeface* tf = find_typeface(*names++, SkTypeface::kNormal); + if (tf) { + gDefaultNormal = tf; + break; + } + } + // check if we found *something* + if (NULL == gDefaultNormal) { + if (NULL == gFamilyHead) { + sk_throw(); + } + for (int i = 0; i < 4; i++) { + if ((gDefaultNormal = gFamilyHead->fFaces[i]) != NULL) { + break; + } + } + } + if (NULL == gDefaultNormal) { + sk_throw(); + } + gFallBackTypeface = gDefaultNormal; + gDefaultFamily = find_family(gDefaultNormal); + +// SkDebugf("---- default %p head %p family %p\n", gDefaultNormal, gFamilyHead, gDefaultFamily); +} + +/////////////////////////////////////////////////////////////////////////////// + +void SkFontHost::Serialize(const SkTypeface* face, SkWStream* stream) { +#if 0 + const char* name = ((FamilyTypeface*)face)->getUniqueString(); + + stream->write8((uint8_t)face->getStyle()); + + if (NULL == name || 0 == *name) { + stream->writePackedUInt(0); + // SkDebugf("--- fonthost serialize null\n"); + } else { + uint32_t len = strlen(name); + stream->writePackedUInt(len); + stream->write(name, len); + // SkDebugf("--- fonthost serialize <%s> %d\n", name, face->getStyle()); + } +#endif + sk_throw(); +} + +SkTypeface* SkFontHost::Deserialize(SkStream* stream) { +#if 0 + load_system_fonts(); + + int style = stream->readU8(); + + int len = stream->readPackedUInt(); + if (len > 0) { + SkString str; + str.resize(len); + stream->read(str.writable_str(), len); + + const FontInitRec* rec = gSystemFonts; + for (size_t i = 0; i < SK_ARRAY_COUNT(gSystemFonts); i++) { + if (strcmp(rec[i].fFileName, str.c_str()) == 0) { + // backup until we hit the fNames + for (int j = i; j >= 0; --j) { + if (rec[j].fNames != NULL) { + return SkFontHost::FindTypeface(NULL, rec[j].fNames[0], + (SkTypeface::Style)style); + } + } + } + } + } + return SkFontHost::FindTypeface(NULL, NULL, (SkTypeface::Style)style); +#endif + sk_throw(); +} + +/////////////////////////////////////////////////////////////////////////////// + +SkTypeface* SkFontHost::FindTypeface(const SkTypeface* familyFace, + const char familyName[], + SkTypeface::Style style) +{ + load_system_fonts(); + + SkAutoMutexAcquire ac(gFamilyMutex); + + // clip to legal style bits + style = (SkTypeface::Style)(style & SkTypeface::kBoldItalic); + + SkTypeface* tf = NULL; + + if (NULL != familyFace) { + tf = find_typeface(familyFace, style); + } else if (NULL != familyName) { + // SkDebugf("======= familyName <%s>\n", familyName); + tf = find_typeface(familyName, style); + } + + if (NULL == tf) { + tf = find_best_face(gDefaultFamily, style); + } + + return tf; +} + +SkTypeface* SkFontHost::ResolveTypeface(uint32_t fontID) +{ + SkAutoMutexAcquire ac(gFamilyMutex); + + return resolve_uniqueID(fontID); +} + +SkStream* SkFontHost::OpenStream(uint32_t fontID) +{ + + FamilyTypeface* tf = (FamilyTypeface*)SkFontHost::ResolveTypeface(fontID); + SkStream* stream = tf ? tf->openStream() : NULL; + + if (NULL == stream || stream->getLength() == 0) { + delete stream; + stream = NULL; + } + return stream; +} + +void SkFontHost::CloseStream(uint32_t fontID, SkStream* stream) +{ + FamilyTypeface* tf = (FamilyTypeface*)SkFontHost::ResolveTypeface(fontID); + if (NULL != tf) { + tf->closeStream(stream); + } +} + +SkScalerContext* SkFontHost::CreateFallbackScalerContext( + const SkScalerContext::Rec& rec) +{ + load_system_fonts(); + + SkAutoDescriptor ad(sizeof(rec) + SkDescriptor::ComputeOverhead(1)); + SkDescriptor* desc = ad.getDesc(); + + desc->init(); + SkScalerContext::Rec* newRec = + (SkScalerContext::Rec*)desc->addEntry(kRec_SkDescriptorTag, + sizeof(rec), &rec); + newRec->fFontID = gFallBackTypeface->uniqueID(); + desc->computeChecksum(); + + return SkFontHost::CreateScalerContext(desc); +} + +/////////////////////////////////////////////////////////////////////////////// + +SkTypeface* SkFontHost::CreateTypeface(SkStream* stream) +{ + if (NULL == stream || stream->getLength() <= 0) { + SkDELETE(stream); + return NULL; + } + + SkString name; + SkTypeface::Style style = find_name_and_style(stream, &name); + + return SkNEW_ARGS(StreamTypeface, (style, false, NULL, stream)); +} + +/////////////////////////////////////////////////////////////////////////////// + +size_t SkFontHost::ShouldPurgeFontCache(size_t sizeAllocatedSoFar) +{ + if (sizeAllocatedSoFar > FONT_CACHE_MEMORY_BUDGET) + return sizeAllocatedSoFar - FONT_CACHE_MEMORY_BUDGET; + else + return 0; // nothing to do +} + diff --git a/skia/ports/SkFontHost_mac.cpp b/skia/ports/SkFontHost_mac.cpp new file mode 100644 index 0000000..9e1151c --- /dev/null +++ b/skia/ports/SkFontHost_mac.cpp @@ -0,0 +1,562 @@ +/* + ** Copyright 2006, The Android Open Source Project + ** + ** Licensed under the Apache License, Version 2.0 (the "License"); + ** you may not use this file except in compliance with the License. + ** You may obtain a copy of the License at + ** + ** http://www.apache.org/licenses/LICENSE-2.0 + ** + ** Unless required by applicable law or agreed to in writing, software + ** distributed under the License is distributed on an "AS IS" BASIS, + ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ** See the License for the specific language governing permissions and + ** limitations under the License. +*/ + +#include "SkFontHost.h" +#include "SkDescriptor.h" + +// Give 1MB font cache budget +#define FONT_CACHE_MEMORY_BUDGET (1024 * 1024) + +const char* gDefaultfont = "Arial"; // hard code for now +static SkMutex gFTMutex; + +inline SkPoint F32PtToSkPoint(const Float32Point p) +{ + SkPoint sp = { SkFloatToFixed(p.x),SkFloatToFixed(p.y) }; + return sp; +} + +static inline uint32_t _rotl(uint32_t v, uint32_t r) +{ + return (v << r | v >> (32 - r)); +} + +// This will generate a unique ID based on the fontname + fontstyle +// and also used by upper layer +uint32_t FontFaceChecksum(const char *name,SkTypeface::Style style) +{ + if (!name) return style; + + char* q = (char*)name; + + // From "Performance in Practice of String Hashing Functions" + // Ramakrishna & Zobel + const uint32_t L = 5; + const uint32_t R = 2; + + uint32_t h = 0x12345678; + while (*q) { + uint32_t ql = tolower(*q); + h ^= ((h << L) + (h >> R) + ql); + q ++; + } + + // add style + h = _rotl(h, 3) ^ style; + + return h; +} + +#pragma mark - +struct SkFaceRec { + SkFaceRec* fNext; + uint32_t fRefCnt; + ATSUFontID fFontID; + ATSUStyle fStyle; + + SkFaceRec() : fFontID(0), fRefCnt(0), fStyle(NULL) {}; + + ~SkFaceRec() { + if (fStyle) { + ::ATSUDisposeStyle(fStyle); + fStyle = NULL; + } + } + + uint32_t ref() { + return ++fRefCnt; + } +}; + +// Font Face list +static SkFaceRec* gFaceRecHead = NULL; + +static SkFaceRec* find_ft_face(const ATSUFontID fontID) { + SkFaceRec* rec = gFaceRecHead; + while (rec) { + if (rec->fFontID == fontID) { + return rec; + } + rec = rec->fNext; + } + + return NULL; +} + +static SkFaceRec* insert_ft_face(const ATSUFontID afontID, const ATSUStyle atsuStyle) { + SkFaceRec* rec = find_ft_face(afontID); + if (rec) { + return rec; // found? + } + + rec = SkNEW(SkFaceRec); + rec->fFontID = afontID; + rec->fStyle = atsuStyle; + rec->fNext = gFaceRecHead; + gFaceRecHead = rec; + + return rec; +} + +static void unref_ft_face(const ATSUFontID fontID) { + + SkFaceRec* rec = gFaceRecHead; + SkFaceRec* prev = NULL; + while (rec) { + SkFaceRec* next = rec->fNext; + if (rec->fFontID == fontID) { + if (--rec->fRefCnt == 0) { + if (prev) + prev->fNext = next; + else + gFaceRecHead = next; + + SkDELETE(rec); + } + return; + } + prev = rec; + rec = next; + } + SkASSERT("shouldn't get here, face not in list"); +} + +#pragma mark - + +// have to do this because SkTypeface::SkTypeface() is protected +class SkTypeface_Mac : public SkTypeface { +public: + SkTypeface_Mac(SkTypeface::Style style, uint32_t id) : SkTypeface(style, id) {} + + ~SkTypeface_Mac() {} +}; + +#pragma mark - + +static SkTypeface* CreateTypeface_(const char *name, const SkTypeface::Style style) { + + OSStatus err; + ATSUStyle atsuStyle; + ::ATSUCreateStyle(&atsuStyle); + if (name != NULL) { + static const ATSUAttributeTag fontTag = kATSUFontTag; + static const ByteCount fontTagSize = sizeof(ATSUFontID); + + ATSUFontID fontID = 0; +#if 1 + err = ::ATSUFindFontFromName( + name,strlen(name),kFontNoNameCode, /* instead of regular, kFontFamilyName returns bold and/or italic sometimes, but why this works?? */ + kFontMacintoshPlatform,kFontNoScriptCode,kFontNoLanguageCode,&fontID); +#else + CFStringRef cfontName = CFStringCreateWithCString(NULL, name, kCFStringEncodingASCII); + ATSFontRef fontRef = ::ATSFontFindFromName(cfontName,kATSOptionFlagsDefault); + fontID = ::FMGetFontFromATSFontRef(fontRef); + CFRelease(cfontName); +#endif + if (0 != fontID) { + const ATSUAttributeValuePtr values[] = { &fontID }; + err = ::ATSUSetAttributes(atsuStyle,1,&fontTag,&fontTagSize,values); + } + else { + } + } + if (style != SkTypeface::kNormal) { + Boolean fontItalic = ((style & SkTypeface::kItalic) != 0); + Boolean fontBold = ((style & SkTypeface::kBold) != 0); + const ATSUAttributeTag tags[2] = { kATSUQDBoldfaceTag, kATSUQDItalicTag }; + const ATSUAttributeValuePtr values[2] = { &fontBold, &fontItalic }; + const ByteCount sizes[2] = { sizeof(Boolean), sizeof(Boolean) }; + err = ::ATSUSetAttributes(atsuStyle,2,tags,sizes,values); + } + + uint32_t cs = FontFaceChecksum(name,style); + SkTypeface_Mac* ptypeface = new SkTypeface_Mac(style,cs); + + if (NULL == ptypeface) { + SkASSERT(false); + return NULL; + } + + SkFaceRec* rec = insert_ft_face(cs, atsuStyle); + SkASSERT(rec); + + return ptypeface; +} + +static SkTypeface* CreateTypeface_(const SkFaceRec* rec, const SkTypeface::Style style) { + + OSStatus err; + ATSUStyle atsuStyle; + err = ::ATSUCreateAndCopyStyle(rec->fStyle, &atsuStyle); + + Boolean fontItalic = ((style & SkTypeface::kItalic) != 0); + Boolean fontBold = ((style & SkTypeface::kBold) != 0); + const ATSUAttributeTag tags[2] = { kATSUQDBoldfaceTag, kATSUQDItalicTag }; + const ATSUAttributeValuePtr values[2] = { &fontBold, &fontItalic }; + const ByteCount sizes[2] = { sizeof(Boolean), sizeof(Boolean) }; + err = ::ATSUSetAttributes(atsuStyle,2,tags,sizes,values); + + // get old font id and name + ATSUFontID fontID = 0; + ByteCount actual = 0; + err = ::ATSUGetAttribute(rec->fStyle,kATSUFontTag,sizeof(ATSUFontID),&fontID,&actual); + + ByteCount actualLength = 0; + char *fontname = NULL; + err = ::ATSUFindFontName(fontID , kFontFamilyName, kFontUnicodePlatform, kFontNoScriptCode, + kFontNoLanguageCode , 0 , NULL , &actualLength , NULL ); + if ( err == noErr) + { + actualLength += 1 ; + fontname = (char*)malloc( actualLength ); + err = ::ATSUFindFontName(fontID, kFontFamilyName, kFontUnicodePlatform, kFontNoScriptCode, + kFontNoLanguageCode, actualLength, fontname , NULL, NULL); + } + + SkTypeface_Mac* ptypeface = NULL; + if (fontname == NULL) { + ptypeface = new SkTypeface_Mac(style,rec->fFontID); + return ptypeface; + } + else { + uint32_t cs = FontFaceChecksum(fontname,style); + ptypeface = new SkTypeface_Mac(style, cs); + + if (NULL == ptypeface) { + SkASSERT(false); + return NULL; + } + + free(fontname); + + insert_ft_face(cs,atsuStyle); + } + return ptypeface; +} + +#pragma mark - + +class SkScalerContext_Mac : public SkScalerContext { +public: + SkScalerContext_Mac(const SkDescriptor* desc); + virtual ~SkScalerContext_Mac(); + +protected: + virtual unsigned generateGlyphCount() const; + virtual uint16_t generateCharToGlyph(SkUnichar uni); + virtual void generateAdvance(SkGlyph* glyph); + virtual void generateMetrics(SkGlyph* glyph); + virtual void generateImage(const SkGlyph& glyph); + virtual void generatePath(const SkGlyph& glyph, SkPath* path); + virtual void generateLineHeight(SkPoint* ascent, SkPoint* descent); + virtual void generateFontMetrics(SkPaint::FontMetrics* mX, SkPaint::FontMetrics* mY); + virtual SkDeviceContext getDC() { return NULL; } // not implemented on Mac + +private: + ATSUTextLayout fLayout; + ATSUStyle fStyle; + + static OSStatus MoveTo(const Float32Point *pt, void *cb); + static OSStatus Line(const Float32Point *pt, void *cb); + static OSStatus Curve(const Float32Point *pt1, const Float32Point *pt2, const Float32Point *pt3, void *cb); + static OSStatus Close(void *cb); +}; + +SkScalerContext_Mac::SkScalerContext_Mac(const SkDescriptor* desc) + : SkScalerContext(desc), fLayout(0), fStyle(0) +{ + SkAutoMutexAcquire ac(gFTMutex); + OSStatus err; + + SkFaceRec* rec = find_ft_face(fRec.fFontID); + if (rec) { + rec->ref(); + err = ::ATSUCreateAndCopyStyle(rec->fStyle, &fStyle); + } + else { + SkASSERT(false); + // create a default + err = ::ATSUCreateStyle(&fStyle); + } + + uint32_t size = SkFixedFloor(fRec.fTextSize); + Fixed fixedSize = IntToFixed(size); + static const ATSUAttributeTag sizeTag = kATSUSizeTag; + static const ByteCount sizeTagSize = sizeof(Fixed); + const ATSUAttributeValuePtr values[] = { &fixedSize }; + err = ::ATSUSetAttributes(fStyle,1,&sizeTag,&sizeTagSize,values); + + err = ::ATSUCreateTextLayout(&fLayout); +} + +SkScalerContext_Mac::~SkScalerContext_Mac() +{ + unref_ft_face(fRec.fFontID); + + ::ATSUDisposeTextLayout(fLayout); + ::ATSUDisposeStyle(fStyle); +} + +unsigned SkScalerContext_Mac::generateGlyphCount() const +{ + return 0xFFFF; +} + +uint16_t SkScalerContext_Mac::generateCharToGlyph(SkUnichar uni) +{ + SkAutoMutexAcquire ac(gFTMutex); + + OSStatus err; + UniChar achar = uni; + err = ::ATSUSetTextPointerLocation(fLayout,&achar,0,1,1); + err = ::ATSUSetRunStyle(fLayout,fStyle,kATSUFromTextBeginning,kATSUToTextEnd); + + ATSLayoutRecord *layoutPtr; + ItemCount count; + ATSGlyphRef glyph; + + err = ::ATSUDirectGetLayoutDataArrayPtrFromTextLayout(fLayout,0,kATSUDirectDataLayoutRecordATSLayoutRecordCurrent,(void**)&layoutPtr,&count); + glyph = layoutPtr->glyphID; + ::ATSUDirectReleaseLayoutDataArrayPtr(NULL,kATSUDirectDataLayoutRecordATSLayoutRecordCurrent,(void**)&layoutPtr); + return glyph; +} + +void SkScalerContext_Mac::generateAdvance(SkGlyph* glyph) { + this->generateMetrics(glyph); +} + +void SkScalerContext_Mac::generateMetrics(SkGlyph* glyph) +{ + GlyphID glyphID = glyph->fID; + ATSGlyphScreenMetrics metrics= { 0 }; + + glyph->fRsbDelta = 0; + glyph->fLsbDelta = 0; + + OSStatus err = ATSUGlyphGetScreenMetrics(fStyle,1,&glyphID,0,true,true,&metrics); + if (err == noErr) { + glyph->fAdvanceX = SkFloatToFixed(metrics.deviceAdvance.x); + glyph->fAdvanceY = SkFloatToFixed(metrics.deviceAdvance.y); + //glyph->fWidth = metrics.width; + //glyph->fHeight = metrics.height; + glyph->fWidth = metrics.width + ceil(metrics.sideBearing.x - metrics.otherSideBearing.x); + glyph->fHeight = metrics.height + ceil(metrics.sideBearing.y - metrics.otherSideBearing.y) + 1; + + glyph->fTop = -metrics.topLeft.y; + glyph->fLeft = metrics.topLeft.x; + } +} + +void SkScalerContext_Mac::generateFontMetrics(SkPaint::FontMetrics* mx, SkPaint::FontMetrics* my) { + //SkASSERT(false); + if (mx) + memset(mx, 0, sizeof(SkPaint::FontMetrics)); + if (my) + memset(my, 0, sizeof(SkPaint::FontMetrics)); + return; +} + +void SkScalerContext_Mac::generateImage(const SkGlyph& glyph) +{ + SkAutoMutexAcquire ac(gFTMutex); + + GlyphID glyphID = glyph.fID; + ATSGlyphScreenMetrics metrics= { 0 }; + + SkASSERT(fLayout); + OSStatus err = ::ATSUGlyphGetScreenMetrics(fStyle,1,&glyphID,0,true,true,&metrics); + +// uint32_t w = metrics.width; +// uint32_t h = metrics.height; +// uint32_t pitch = (w + 3) & ~0x3; +// if (pitch != glyph.rowBytes()) { +// SkASSERT(false); // it's different from previously cacluated in generateMetrics(), so the size of glyph.fImage buffer is incorrect! +// } + + CGColorSpaceRef greyColorSpace = ::CGColorSpaceCreateWithName(kCGColorSpaceGenericGray); + CGContextRef contextRef = ::CGBitmapContextCreate((uint8_t*)glyph.fImage, glyph.fWidth, glyph.fHeight, 8, glyph.rowBytes(), greyColorSpace, kCGImageAlphaNone); + if (!contextRef) { + SkASSERT(false); + return; + } + + ::CGContextSetFillColorSpace(contextRef, greyColorSpace); + ::CGContextSetStrokeColorSpace(contextRef, greyColorSpace); + + ::CGContextSetGrayFillColor(contextRef, 0.0, 1.0); + ::CGContextFillRect(contextRef, ::CGRectMake(0, 0, glyph.fWidth, glyph.fHeight)); + + ::CGContextSetGrayFillColor(contextRef, 1.0, 1.0); + ::CGContextSetGrayStrokeColor(contextRef, 1.0, 1.0); + ::CGContextSetTextDrawingMode(contextRef, kCGTextFill); + + ATSUAttributeTag tag = kATSUCGContextTag; + ByteCount size = sizeof(CGContextRef); + ATSUAttributeValuePtr value = &contextRef; + err = ::ATSUSetLayoutControls(fLayout,1,&tag,&size,&value); + err = ::ATSUDrawText(fLayout,kATSUFromTextBeginning,kATSUToTextEnd,FloatToFixed(-metrics.topLeft.x),FloatToFixed(glyph.fHeight-metrics.topLeft.y)); + ::CGContextRelease(contextRef); +} + +void SkScalerContext_Mac::generatePath(const SkGlyph& glyph, SkPath* path) +{ + SkAutoMutexAcquire ac(gFTMutex); + OSStatus err,result; + + err = ::ATSUGlyphGetCubicPaths( + fStyle,glyph.fID, + &SkScalerContext_Mac::MoveTo, + &SkScalerContext_Mac::Line, + &SkScalerContext_Mac::Curve, + &SkScalerContext_Mac::Close, + path,&result); + SkASSERT(err == noErr); +} + +void SkScalerContext_Mac::generateLineHeight(SkPoint* ascent, SkPoint* descent) +{ + ATSUTextMeasurement textAscent, textDescent; + ByteCount actual = 0; + OSStatus err = ::ATSUGetAttribute(fStyle,kATSULineAscentTag,sizeof(ATSUTextMeasurement),&textAscent,&actual); + ascent->set(0,textAscent); + err = ::ATSUGetAttribute(fStyle,kATSULineDescentTag,sizeof(ATSUTextMeasurement),&textDescent,&actual); + descent->set(0,textDescent); +} + +OSStatus SkScalerContext_Mac::MoveTo(const Float32Point *pt, void *cb) +{ + reinterpret_cast<SkPath*>(cb)->moveTo(F32PtToSkPoint(*pt)); + return noErr; +} + +OSStatus SkScalerContext_Mac::Line(const Float32Point *pt, void *cb) +{ + reinterpret_cast<SkPath*>(cb)->lineTo(F32PtToSkPoint(*pt)); + return noErr; +} + +OSStatus SkScalerContext_Mac::Curve(const Float32Point *pt1, const Float32Point *pt2, const Float32Point *pt3, void *cb) +{ + reinterpret_cast<SkPath*>(cb)->cubicTo(F32PtToSkPoint(*pt1),F32PtToSkPoint(*pt2),F32PtToSkPoint(*pt3)); + return noErr; +} + +OSStatus SkScalerContext_Mac::Close(void *cb) +{ + reinterpret_cast<SkPath*>(cb)->close(); + return noErr; +} + +#pragma mark - + +void SkFontHost::Serialize(const SkTypeface* face, SkWStream* stream) { + SkASSERT(!"SkFontHost::Serialize unimplemented"); +} + +SkTypeface* SkFontHost::Deserialize(SkStream* stream) { + SkASSERT(!"SkFontHost::Deserialize unimplemented"); + return NULL; +} + +SkTypeface* SkFontHost::CreateTypeface(SkStream* stream) { + + //Should not be used on Mac, keep linker happy + SkASSERT(false); + return CreateTypeface_(gDefaultfont,SkTypeface::kNormal); +} + +SkScalerContext* SkFontHost::CreateScalerContext(const SkDescriptor* desc) +{ + return new SkScalerContext_Mac(desc); +} + +SkScalerContext* SkFontHost::CreateFallbackScalerContext(const SkScalerContext::Rec& rec) +{ + SkAutoDescriptor ad(sizeof(rec) + sizeof(gDefaultfont) + SkDescriptor::ComputeOverhead(2)); + SkDescriptor* desc = ad.getDesc(); + + desc->init(); + SkScalerContext::Rec* newRec = + (SkScalerContext::Rec*)desc->addEntry(kRec_SkDescriptorTag, sizeof(rec), &rec); + + CreateTypeface_(gDefaultfont,SkTypeface::kNormal); + newRec->fFontID = FontFaceChecksum(gDefaultfont,SkTypeface::kNormal); + desc->computeChecksum(); + + return SkFontHost::CreateScalerContext(desc); +} + + + /** Return the closest matching typeface given either an existing family + (specified by a typeface in that family) or by a familyName, and a + requested style. + 1) If familyFace is null, use famillyName. + 2) If famillyName is null, use familyFace. + 3) If both are null, return the default font that best matches style + This MUST not return NULL. + */ + +SkTypeface* SkFontHost::FindTypeface(const SkTypeface* familyFace, const char familyName[], SkTypeface::Style style) { + + SkAutoMutexAcquire ac(gFTMutex); + + // clip to legal style bits + style = (SkTypeface::Style)(style & SkTypeface::kBoldItalic); + + SkTypeface* tf = NULL; + + if (NULL == familyFace && NULL == familyName) { + tf = CreateTypeface_(gDefaultfont,style); + } + else { + if (NULL != familyFace) { + uint32_t id = familyFace->uniqueID(); + SkFaceRec* rec = find_ft_face(id); + if (!rec) { + SkASSERT(false); + tf = CreateTypeface_(gDefaultfont,style); + } + else { + tf = CreateTypeface_(rec,style); + } + } + else { + tf = CreateTypeface_(familyName,style); + } + } + + if (NULL == tf) { + tf = CreateTypeface_(gDefaultfont,style); + } + return tf; + +} + +size_t SkFontHost::ShouldPurgeFontCache(size_t sizeAllocatedSoFar) { + if (sizeAllocatedSoFar > FONT_CACHE_MEMORY_BUDGET) + return sizeAllocatedSoFar - FONT_CACHE_MEMORY_BUDGET; + else + return 0; // nothing to do +} + +int SkFontHost::ComputeGammaFlag(const SkPaint& paint) { + return 0; +} + +void SkFontHost::GetGammaTables(const uint8_t* tables[2]) { + tables[0] = NULL; // black gamma (e.g. exp=1.4) + tables[1] = NULL; // white gamma (e.g. exp= 1/1.4) +} diff --git a/skia/ports/SkFontHost_none.cpp b/skia/ports/SkFontHost_none.cpp index 4e75abc..b45cf16 100644 --- a/skia/ports/SkFontHost_none.cpp +++ b/skia/ports/SkFontHost_none.cpp @@ -1,4 +1,4 @@ -/* Copyright 2006-2008, Google Inc. +/* Copyright 2006-2008, The Android Open Source Project ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. @@ -17,74 +17,66 @@ SkTypeface* SkFontHost::FindTypeface(const SkTypeface* familyFace, const char famillyName[], - SkTypeface::Style style) -{ + SkTypeface::Style style) { SkASSERT(!"SkFontHost::FindTypeface unimplemented"); return NULL; } -SkTypeface* SkFontHost::ResolveTypeface(uint32_t uniqueID) -{ +SkTypeface* SkFontHost::ResolveTypeface(uint32_t uniqueID) { SkASSERT(!"SkFontHost::ResolveTypeface unimplemented"); return NULL; } -SkStream* SkFontHost::OpenStream(uint32_t uniqueID) -{ +SkStream* SkFontHost::OpenStream(uint32_t uniqueID) { SkASSERT(!"SkFontHost::OpenStream unimplemented"); return NULL; } -void SkFontHost::CloseStream(uint32_t uniqueID, SkStream*) -{ +void SkFontHost::CloseStream(uint32_t uniqueID, SkStream*) { SkASSERT(!"SkFontHost::CloseStream unimplemented"); } -SkTypeface* SkFontHost::CreateTypeface(SkStream*) -{ +SkTypeface* SkFontHost::CreateTypeface(SkStream*) { SkASSERT(!"SkFontHost::CreateTypeface unimplemented"); return NULL; } /////////////////////////////////////////////////////////////////////////////// -SkScalerContext* SkFontHost::CreateScalerContext(const SkDescriptor* desc) -{ +void SkFontHost::Serialize(const SkTypeface* face, SkWStream* stream) { + SkASSERT(!"SkFontHost::Serialize unimplemented"); +} + +SkTypeface* SkFontHost::Deserialize(SkStream* stream) { + SkASSERT(!"SkFontHost::Deserialize unimplemented"); + return NULL; +} + +/////////////////////////////////////////////////////////////////////////////// + +SkScalerContext* SkFontHost::CreateScalerContext(const SkDescriptor* desc) { SkASSERT(!"SkFontHost::CreateScalarContext unimplemented"); return NULL; } -SkScalerContext* SkFontHost::CreateFallbackScalerContext(const SkScalerContext::Rec&) -{ +SkScalerContext* SkFontHost::CreateFallbackScalerContext( + const SkScalerContext::Rec&) { SkASSERT(!"SkFontHost::CreateFallbackScalerContext unimplemented"); return NULL; } /////////////////////////////////////////////////////////////////////////////// -size_t SkFontHost::ShouldPurgeFontCache(size_t sizeAllocatedSoFar) -{ +size_t SkFontHost::ShouldPurgeFontCache(size_t sizeAllocatedSoFar) { return 0; // nothing to do (change me if you want to limit the font cache) } -int SkFontHost::ComputeGammaFlag(const SkPaint& paint) -{ +int SkFontHost::ComputeGammaFlag(const SkPaint& paint) { return 0; } -void SkFontHost::GetGammaTables(const uint8_t* tables[2]) -{ +void SkFontHost::GetGammaTables(const uint8_t* tables[2]) { tables[0] = NULL; // black gamma (e.g. exp=1.4) tables[1] = NULL; // white gamma (e.g. exp= 1/1.4) } -/////////////////////////////////////////////////////////////////////////////// - -SkTypeface* SkFontHost::Deserialize(SkStream* stream) { - SkASSERT(!"SkFontHost::Deserialize unimplemented"); - return NULL; -} - -void SkFontHost::Serialize(const SkTypeface*, SkWStream*) { - SkASSERT(!"SkFontHost::Serialize unimplemented"); -} diff --git a/skia/ports/SkFontHost_win.cpp b/skia/ports/SkFontHost_win.cpp index d66297a..4df55c9 100644 --- a/skia/ports/SkFontHost_win.cpp +++ b/skia/ports/SkFontHost_win.cpp @@ -1,12 +1,32 @@ -/* libs/graphics/ports/SkFontHost_win.cpp +/* -** + ** Copyright 2006, The Android Open Source Project -** Copyright 2006, Google Inc. + ** -** + ** Licensed under the Apache License, Version 2.0 (the "License"); -*/ + ** you may not use this file except in compliance with the License. + + ** You may obtain a copy of the License at + + ** + + ** http://www.apache.org/licenses/LICENSE-2.0 + + ** + + ** Unless required by applicable law or agreed to in writing, software + + ** distributed under the License is distributed on an "AS IS" BASIS, + + ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + + ** See the License for the specific language governing permissions and + + ** limitations under the License. + + */ @@ -32,11 +52,19 @@ -static SkMutex gFTMutex; +// client3d has to undefine this for now + +#define CAN_USE_LOGFONT_NAME + + +static SkMutex gFTMutex; -static LOGFONT gDefaultFont; + +// these globals are loaded (once) by get_default_font() + +static LOGFONT gDefaultFont = {0}; @@ -46,15 +74,13 @@ static uint8_t glyphbuf[BUFFERSIZE]; -#ifndef SK_FONTKEY +// Give 1MB font cache budget - #define SK_FONTKEY "Windows Font Key" - -#endif +#define FONT_CACHE_MEMORY_BUDGET (1024 * 1024) -inline FIXED SkFixedToFIXED(SkFixed x) { +static inline FIXED SkFixedToFIXED(SkFixed x) { return *(FIXED*)(&x); @@ -62,81 +88,257 @@ inline FIXED SkFixedToFIXED(SkFixed x) { -class FontFaceRec_Typeface : public SkTypeface { +static inline FIXED SkScalarToFIXED(SkScalar x) { + + return SkFixedToFIXED(SkScalarToFixed(x)); + +} -public: -#if 0 - FontFaceRec_Typeface(const LOGFONT& face) : fFace(face) +// This will generate a unique ID based on the fontname + fontstyle - { +// and also used by upper layer - int style = 0; +uint32_t FontFaceChecksum(const TCHAR *q, SkTypeface::Style style) - if (face.lfWeight == FW_SEMIBOLD || face.lfWeight == FW_DEMIBOLD || face.lfWeight == FW_BOLD) +{ + + if (!q) return style; - style |= SkTypeface::kBold; + - if (face.lfItalic) + // From "Performance in Practice of String Hashing Functions" - style |= SkTypeface::kItalic; + // Ramakrishna & Zobel - this->setStyle((SkTypeface::Style)style); + const uint32_t L = 5; + + const uint32_t R = 2; + + + + uint32_t h = 0x12345678; + + while (*q) { + + //uint32_t ql = tolower(*q); + + h ^= ((h << L) + (h >> R) + *q); + + q ++; } -#endif + - ~FontFaceRec_Typeface() {}; + // add style + h = _rotl(h, 3) ^ style; + - TCHAR* GetFontName() { return fFace.lfFaceName; } + return h; +} - SkTypeface::Style GetFontStyle() { - int style = SkTypeface::kNormal; +static SkTypeface::Style GetFontStyle(const LOGFONT& lf) { - if (fFace.lfWeight == FW_SEMIBOLD || fFace.lfWeight == FW_DEMIBOLD || fFace.lfWeight == FW_BOLD) + int style = SkTypeface::kNormal; - style |= SkTypeface::kBold; + if (lf.lfWeight == FW_SEMIBOLD || lf.lfWeight == FW_DEMIBOLD || lf.lfWeight == FW_BOLD) - if (fFace.lfItalic) + style |= SkTypeface::kBold; - style |= SkTypeface::kItalic; + if (lf.lfItalic) + style |= SkTypeface::kItalic; + - return (SkTypeface::Style)style; + return (SkTypeface::Style)style; - } +} + + + +struct SkFaceRec { + + SkFaceRec* fNext; + + uint32_t fRefCnt; + + uint32_t fFontID; // checksum of fFace + + LOGFONT fFace; + + + + SkFaceRec() : fFontID(-1), fRefCnt(0) { + memset(&fFace, 0, sizeof(LOGFONT)); + } + + ~SkFaceRec() {} - long GetFontSize() { return fFace.lfHeight; } + + uint32_t ref() { + return ++fRefCnt; - LOGFONT fFace; + } }; +// Font Face list +static SkFaceRec* gFaceRecHead = NULL; -static const LOGFONT* get_default_font() -{ + +static SkFaceRec* find_ft_face(uint32_t fontID) { + + SkFaceRec* rec = gFaceRecHead; + + while (rec) { + + if (rec->fFontID == fontID) { + + return rec; + + } + + rec = rec->fNext; + + } + + + + return NULL; + +} + + + +static SkFaceRec* insert_ft_face(const LOGFONT& lf) { + + // need a const char* + + uint32_t id = FontFaceChecksum(&(lf.lfFaceName[0]), GetFontStyle(lf)); + + SkFaceRec* rec = find_ft_face(id); + + if (rec) { + + return rec; // found? + + } + + + + rec = SkNEW(SkFaceRec); + + rec->fFontID = id; + + memcpy(&(rec->fFace), &lf, sizeof(LOGFONT)); + + rec->fNext = gFaceRecHead; + + gFaceRecHead = rec; + + + + return rec; + +} + + + +static void unref_ft_face(uint32_t fontID) { + + + + SkFaceRec* rec = gFaceRecHead; + + SkFaceRec* prev = NULL; + + while (rec) { + + SkFaceRec* next = rec->fNext; + + if (rec->fFontID == fontID) { + + if (--rec->fRefCnt == 0) { + + if (prev) + + prev->fNext = next; + + else + + gFaceRecHead = next; + + + + SkDELETE(rec); + + } + + return; + + } + + prev = rec; + + rec = next; + + } + + SkASSERT("shouldn't get here, face not in list"); + +} + + + +// have to do this because SkTypeface::SkTypeface() is protected + +class FontFaceRec_Typeface : public SkTypeface { + +public: + + + + FontFaceRec_Typeface(Style style, uint32_t id) : SkTypeface(style, id) {}; + + + + virtual ~FontFaceRec_Typeface() {}; + +}; + + + +static const LOGFONT* get_default_font() { // don't hardcode on Windows, Win2000, XP, Vista, and international all have different default // and the user could change too + + + if (gDefaultFont.lfFaceName[0] != 0) { + + return &gDefaultFont; + } + + NONCLIENTMETRICS ncm; @@ -144,11 +346,11 @@ static const LOGFONT* get_default_font() SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, 0); - + memcpy(&gDefaultFont, &(ncm.lfMessageFont), sizeof(LOGFONT)); - + return &gDefaultFont; @@ -156,33 +358,33 @@ static const LOGFONT* get_default_font() -static uint32_t FontFaceChecksum(const LOGFONT& face) - -{ - - uint32_t cs = 0; +static SkTypeface* CreateTypeface_(const LOGFONT& lf) { - uint32_t bytesize = sizeof(LOGFONT); + - bytesize >>= 2; + SkTypeface::Style style = GetFontStyle(lf); - uint32_t *p32 = (uint32_t*)&face; + FontFaceRec_Typeface* ptypeface = new FontFaceRec_Typeface(style, FontFaceChecksum(lf.lfFaceName, style)); + + if (NULL == ptypeface) { - while (bytesize) { + SkASSERT(false); - bytesize --; + return NULL; - cs ^= *p32; + } - p32 ++; + - } + SkFaceRec* rec = insert_ft_face(lf); + SkASSERT(rec); + - return cs; + return ptypeface; } @@ -196,7 +398,7 @@ public: virtual ~SkScalerContext_Windows(); - + protected: @@ -204,6 +406,8 @@ protected: virtual uint16_t generateCharToGlyph(SkUnichar uni); + virtual void generateAdvance(SkGlyph* glyph); + virtual void generateMetrics(SkGlyph* glyph); virtual void generateImage(const SkGlyph& glyph); @@ -212,43 +416,77 @@ protected: virtual void generateLineHeight(SkPoint* ascent, SkPoint* descent); + virtual void generateFontMetrics(SkPaint::FontMetrics* mX, SkPaint::FontMetrics* mY); + //virtual SkDeviceContext getDC() {return ddc;} private: - LOGFONT* plf; + uint32_t fFontID; + + LOGFONT lf; MAT2 mat22; -}; + HDC ddc; + HFONT savefont; + HFONT font; -SkScalerContext_Windows::SkScalerContext_Windows(const SkDescriptor* desc) +}; - : SkScalerContext(desc), plf(NULL) -{ + +SkScalerContext_Windows::SkScalerContext_Windows(const SkDescriptor* desc) : SkScalerContext(desc), ddc(0), font(0), savefont(0) { SkAutoMutexAcquire ac(gFTMutex); + + fFontID = fRec.fFontID; - const LOGFONT** face = (const LOGFONT**)desc->findEntry(kTypeface_SkDescriptorTag, NULL); + SkFaceRec* rec = find_ft_face(fRec.fFontID); - plf = (LOGFONT*)*face; + if (rec) { - SkASSERT(plf); + rec->ref(); - + memcpy(&lf, &(rec->fFace), sizeof(LOGFONT)); - mat22.eM11 = SkFixedToFIXED(fRec.fPost2x2[0][0]); + } + + else { - mat22.eM12 = SkFixedToFIXED(-fRec.fPost2x2[0][1]); + SkASSERT(false); - mat22.eM21 = SkFixedToFIXED(fRec.fPost2x2[1][0]); + memcpy(&lf, &gDefaultFont, sizeof(LOGFONT)); - mat22.eM22 = SkFixedToFIXED(-fRec.fPost2x2[1][1]); + } + + + + mat22.eM11 = SkScalarToFIXED(fRec.fPost2x2[0][0]); + + mat22.eM12 = SkScalarToFIXED(-fRec.fPost2x2[0][1]); + + mat22.eM21 = SkScalarToFIXED(fRec.fPost2x2[1][0]); + + mat22.eM22 = SkScalarToFIXED(-fRec.fPost2x2[1][1]); + + + + ddc = ::CreateCompatibleDC(NULL); + + SetBkMode(ddc, TRANSPARENT); + + + + lf.lfHeight = SkScalarFloor(fRec.fTextSize); + + font = CreateFontIndirect(&lf); + + savefont = (HFONT)SelectObject(ddc, font); } @@ -256,6 +494,26 @@ SkScalerContext_Windows::SkScalerContext_Windows(const SkDescriptor* desc) SkScalerContext_Windows::~SkScalerContext_Windows() { + unref_ft_face(fFontID); + + + + if (ddc) { + + ::SelectObject(ddc, savefont); + + ::DeleteDC(ddc); + + ddc = NULL; + + } + + if (font) { + + ::DeleteObject(font); + + } + } @@ -264,7 +522,7 @@ unsigned SkScalerContext_Windows::generateGlyphCount() const { return 0xFFFF; -// return fFace->num_glyphs; + // return fFace->num_glyphs; } @@ -272,35 +530,37 @@ unsigned SkScalerContext_Windows::generateGlyphCount() const { uint16_t SkScalerContext_Windows::generateCharToGlyph(SkUnichar uni) { + + //uint16_t index = 0; - // let's just use the uni as index on Windows - - return SkToU16(uni); - -} + //GetGlyphIndicesW(ddc, &(uint16_t&)uni, 1, &index, 0); + //return index; + -void SkScalerContext_Windows::generateMetrics(SkGlyph* glyph) { + // let's just use the uni as index on Windows + return SkToU16(uni); +} - HDC ddc = ::CreateCompatibleDC(NULL); - SetBkMode(ddc, TRANSPARENT); +void SkScalerContext_Windows::generateAdvance(SkGlyph* glyph) { + this->generateMetrics(glyph); - SkASSERT(plf); +} - plf->lfHeight = -SkFixedFloor(fRec.fTextSize); +void SkScalerContext_Windows::generateMetrics(SkGlyph* glyph) { - HFONT font = CreateFontIndirect(plf); + - HFONT oldfont = (HFONT)SelectObject(ddc, font); + SkASSERT(ddc); @@ -308,19 +568,23 @@ void SkScalerContext_Windows::generateMetrics(SkGlyph* glyph) { memset(&gm, 0, sizeof(gm)); - + glyph->fRsbDelta = 0; glyph->fLsbDelta = 0; + + + UINT glyphIndexFlag = 0; //glyph->fIsCodePoint ? 0 : GGO_GLYPH_INDEX; + // UINT glyphIndexFlag = GGO_GLYPH_INDEX; // Note: need to use GGO_GRAY8_BITMAP instead of GGO_METRICS because GGO_METRICS returns a smaller // BlackBlox; we need the bigger one in case we need the image. fAdvance is the same. - uint32_t ret = GetGlyphOutlineW(ddc, glyph->f_GlyphID, GGO_GRAY8_BITMAP, &gm, 0, NULL, &mat22); + uint32_t ret = GetGlyphOutlineW(ddc, glyph->getGlyphID(0), GGO_GRAY8_BITMAP | glyphIndexFlag, &gm, 0, NULL, &mat22); @@ -338,63 +602,91 @@ void SkScalerContext_Windows::generateMetrics(SkGlyph* glyph) { glyph->fHeight = gm.gmBlackBoxY; - glyph->fTop = gm.gmptGlyphOrigin.y - gm.gmBlackBoxY; + glyph->fTop = SkToS16(gm.gmptGlyphOrigin.y - gm.gmBlackBoxY); - glyph->fLeft = gm.gmptGlyphOrigin.x; + glyph->fLeft = SkToS16(gm.gmptGlyphOrigin.x); glyph->fAdvanceX = SkIntToFixed(gm.gmCellIncX); glyph->fAdvanceY = -SkIntToFixed(gm.gmCellIncY); + } else { + + glyph->fWidth = 0; + } + +#if 0 - ::SelectObject(ddc, oldfont); + char buf[1024]; - ::DeleteObject(font); + sprintf(buf, "generateMetrics: id:%d, w=%d, h=%d, font:%s, fh:%d\n", glyph->fID, glyph->fWidth, glyph->fHeight, lf.lfFaceName, lf.lfHeight); - ::DeleteDC(ddc); + OutputDebugString(buf); + +#endif } -void SkScalerContext_Windows::generateImage(const SkGlyph& glyph) { +void SkScalerContext_Windows::generateFontMetrics(SkPaint::FontMetrics* mx, SkPaint::FontMetrics* my) { + //SkASSERT(false); + if (mx) - SkAutoMutexAcquire ac(gFTMutex); + memset(mx, 0, sizeof(SkPaint::FontMetrics)); + if (my) + memset(my, 0, sizeof(SkPaint::FontMetrics)); - SkASSERT(plf); + return; +} - HDC ddc = ::CreateCompatibleDC(NULL); - SetBkMode(ddc, TRANSPARENT); +void SkScalerContext_Windows::generateImage(const SkGlyph& glyph) { + + SkAutoMutexAcquire ac(gFTMutex); - plf->lfHeight = -SkFixedFloor(fRec.fTextSize); + + SkASSERT(ddc); + - HFONT font = CreateFontIndirect(plf); + GLYPHMETRICS gm; - HFONT oldfont = (HFONT)SelectObject(ddc, font); + memset(&gm, 0, sizeof(gm)); + + +#if 0 + char buf[1024]; - GLYPHMETRICS gm; + sprintf(buf, "generateImage: id:%d, w=%d, h=%d, font:%s,fh:%d\n", glyph.fID, glyph.fWidth, glyph.fHeight, lf.lfFaceName, lf.lfHeight); - memset(&gm, 0, sizeof(gm)); + OutputDebugString(buf); +#endif + + + uint32_t bytecount = 0; - uint32_t total_size = GetGlyphOutlineW(ddc, glyph.f_GlyphID, GGO_GRAY8_BITMAP, &gm, 0, NULL, &mat22); + UINT glyphIndexFlag = 0; //glyph.fIsCodePoint ? 0 : GGO_GLYPH_INDEX; + + // UINT glyphIndexFlag = GGO_GLYPH_INDEX; + + uint32_t total_size = GetGlyphOutlineW(ddc, glyph.fID, GGO_GRAY8_BITMAP | glyphIndexFlag, &gm, 0, NULL, &mat22); if (GDI_ERROR != total_size && total_size > 0) { @@ -402,25 +694,37 @@ void SkScalerContext_Windows::generateImage(const SkGlyph& glyph) { if (NULL != pBuff) { - total_size = GetGlyphOutlineW(ddc, glyph.f_GlyphID, GGO_GRAY8_BITMAP, &gm, total_size, pBuff, &mat22); + total_size = GetGlyphOutlineW(ddc, glyph.fID, GGO_GRAY8_BITMAP | glyphIndexFlag, &gm, total_size, pBuff, &mat22); - + SkASSERT(total_size != GDI_ERROR); + + + SkASSERT(glyph.fWidth == gm.gmBlackBoxX); + SkASSERT(glyph.fHeight == gm.gmBlackBoxY); + + uint8_t* dst = (uint8_t*)glyph.fImage; uint32_t pitch = (gm.gmBlackBoxX + 3) & ~0x3; + if (pitch != glyph.rowBytes()) { + + SkASSERT(false); // glyph.fImage has different rowsize!? + } + + for (int32_t y = gm.gmBlackBoxY - 1; y >= 0; y--) { uint8_t* src = pBuff + pitch * y; - + for (uint32_t x = 0; x < gm.gmBlackBoxX; x++) { @@ -440,11 +744,17 @@ void SkScalerContext_Windows::generateImage(const SkGlyph& glyph) { src++; + bytecount++; + } - } + memset(dst, 0, glyph.rowBytes() - glyph.fWidth); + + dst += glyph.rowBytes() - glyph.fWidth; + } + delete[] pBuff; @@ -452,17 +762,11 @@ void SkScalerContext_Windows::generateImage(const SkGlyph& glyph) { } - + SkASSERT(GDI_ERROR != total_size && total_size >= 0); - - - ::SelectObject(ddc, oldfont); - - ::DeleteObject(font); - - ::DeleteDC(ddc); + } @@ -470,91 +774,85 @@ void SkScalerContext_Windows::generateImage(const SkGlyph& glyph) { void SkScalerContext_Windows::generatePath(const SkGlyph& glyph, SkPath* path) { - + SkAutoMutexAcquire ac(gFTMutex); - + SkASSERT(&glyph && path); + SkASSERT(ddc); - - SkASSERT(plf); - - + path->reset(); + +#if 0 - HDC ddc = ::CreateCompatibleDC(NULL); - - SetBkMode(ddc, TRANSPARENT); - - - - plf->lfHeight = -SkFixedFloor(fRec.fTextSize); - - + char buf[1024]; - HFONT font = CreateFontIndirect(plf); + sprintf(buf, "generatePath: id:%d, w=%d, h=%d, font:%s,fh:%d\n", glyph.fID, glyph.fWidth, glyph.fHeight, lf.lfFaceName, lf.lfHeight); - HFONT oldfont = (HFONT)SelectObject(ddc, font); + OutputDebugString(buf); +#endif + GLYPHMETRICS gm; + UINT glyphIndexFlag = 0; //glyph.fIsCodePoint ? 0 : GGO_GLYPH_INDEX; + uint32_t total_size = GetGlyphOutlineW(ddc, glyph.fID, GGO_NATIVE | glyphIndexFlag, &gm, BUFFERSIZE, glyphbuf, &mat22); - uint32_t total_size = GetGlyphOutlineW(ddc, glyph.f_GlyphID, GGO_NATIVE, &gm, BUFFERSIZE, glyphbuf, &mat22); - - + if (GDI_ERROR != total_size) { - + const uint8_t* cur_glyph = glyphbuf; const uint8_t* end_glyph = glyphbuf + total_size; - + while(cur_glyph < end_glyph) { const TTPOLYGONHEADER* th = (TTPOLYGONHEADER*)cur_glyph; - + const uint8_t* end_poly = cur_glyph + th->cb; const uint8_t* cur_poly = cur_glyph + sizeof(TTPOLYGONHEADER); - + - path->moveTo(*(SkFixed*)(&th->pfxStart.x), *(SkFixed*)(&th->pfxStart.y)); + path->moveTo(SkFixedToScalar(*(SkFixed*)(&th->pfxStart.x)), SkFixedToScalar(*(SkFixed*)(&th->pfxStart.y))); - + while(cur_poly < end_poly) { const TTPOLYCURVE* pc = (const TTPOLYCURVE*)cur_poly; - + if (pc->wType == TT_PRIM_LINE) { for (uint16_t i = 0; i < pc->cpfx; i++) { - path->lineTo(*(SkFixed*)(&pc->apfx[i].x), *(SkFixed*)(&pc->apfx[i].y)); + path->lineTo(SkFixedToScalar(*(SkFixed*)(&pc->apfx[i].x)), SkFixedToScalar(*(SkFixed*)(&pc->apfx[i].y))); } } - + if (pc->wType == TT_PRIM_QSPLINE) { @@ -564,7 +862,7 @@ void SkScalerContext_Windows::generatePath(const SkGlyph& glyph, SkPath* path) { POINTFX pnt_c = pc->apfx[u+1]; - + if (u < pc->cpfx - 2) { // If not on last spline, compute C @@ -574,9 +872,9 @@ void SkScalerContext_Windows::generatePath(const SkGlyph& glyph, SkPath* path) { } + - - path->quadTo(*(SkFixed*)(&pnt_b.x), *(SkFixed*)(&pnt_b.y), *(SkFixed*)(&pnt_c.x), *(SkFixed*)(&pnt_c.y)); + path->quadTo(SkFixedToScalar(*(SkFixed*)(&pnt_b.x)), SkFixedToScalar(*(SkFixed*)(&pnt_b.y)), SkFixedToScalar(*(SkFixed*)(&pnt_c.x)), SkFixedToScalar(*(SkFixed*)(&pnt_c.y))); } @@ -588,6 +886,8 @@ void SkScalerContext_Windows::generatePath(const SkGlyph& glyph, SkPath* path) { cur_glyph += th->cb; + path->close(); + } } @@ -598,17 +898,11 @@ void SkScalerContext_Windows::generatePath(const SkGlyph& glyph, SkPath* path) { } + //char buf[1024]; + //sprintf(buf, "generatePath: count:%d\n", count); - path->close(); - - - - ::SelectObject(ddc, oldfont); - - ::DeleteObject(font); - - ::DeleteDC(ddc); + //OutputDebugString(buf); } @@ -620,33 +914,19 @@ void SkScalerContext_Windows::generatePath(const SkGlyph& glyph, SkPath* path) { void SkScalerContext_Windows::generateLineHeight(SkPoint* ascent, SkPoint* descent) { + + SkASSERT(ddc); - HDC ddc = ::CreateCompatibleDC(NULL); - - SetBkMode(ddc, TRANSPARENT); - - - - SkASSERT(plf); - - plf->lfHeight = -SkFixedFloor(fRec.fTextSize); - - - - HFONT font = CreateFontIndirect(plf); - - HFONT oldfont = (HFONT)SelectObject(ddc, font); - - + OUTLINETEXTMETRIC otm; - + uint32_t ret = GetOutlineTextMetrics(ddc, sizeof(otm), &otm); - + if (sizeof(otm) == ret) { @@ -660,15 +940,7 @@ void SkScalerContext_Windows::generateLineHeight(SkPoint* ascent, SkPoint* desce } - - - ::SelectObject(ddc, oldfont); - - ::DeleteObject(font); - - ::DeleteDC(ddc); - - + return; @@ -676,213 +948,237 @@ void SkScalerContext_Windows::generateLineHeight(SkPoint* ascent, SkPoint* desce -SkTypeface* SkFontHost::CreateTypeface( const SkTypeface* familyFace, const char familyName[], SkTypeface::Style style) { - - - - FontFaceRec_Typeface* ptypeface = new FontFaceRec_Typeface; +void SkFontHost::Serialize(const SkTypeface* face, SkWStream* stream) { + SkASSERT(!"SkFontHost::Serialize unimplemented"); +} - if (NULL == ptypeface) { - SkASSERT(false); - return NULL; +SkTypeface* SkFontHost::Deserialize(SkStream* stream) { - } + SkASSERT(!"SkFontHost::Deserialize unimplemented"); + return NULL; +} - memset(&ptypeface->fFace, 0, sizeof(LOGFONT)); +SkTypeface* SkFontHost::CreateTypeface(SkStream* stream) { - // default + - ptypeface->fFace.lfHeight = -11; // default + //Should not be used on Windows, keep linker happy - ptypeface->fFace.lfWeight = (style & SkTypeface::kBold) != 0 ? FW_BOLD : FW_NORMAL ; + SkASSERT(false); - ptypeface->fFace.lfItalic = ((style & SkTypeface::kItalic) != 0); + get_default_font(); - ptypeface->fFace.lfQuality = PROOF_QUALITY; + return CreateTypeface_(gDefaultFont); +} - _tcscpy(ptypeface->fFace.lfFaceName, familyName); +SkScalerContext* SkFontHost::CreateScalerContext(const SkDescriptor* desc) { + return SkNEW_ARGS(SkScalerContext_Windows, (desc)); +} - return ptypeface; -} +SkScalerContext* SkFontHost::CreateFallbackScalerContext(const SkScalerContext::Rec& rec) { + get_default_font(); + -uint32_t SkFontHost::FlattenTypeface(const SkTypeface* tface, void* buffer) { + SkAutoDescriptor ad(sizeof(rec) + sizeof(gDefaultFont) + SkDescriptor::ComputeOverhead(2)); - const LOGFONT* face; + SkDescriptor* desc = ad.getDesc(); - if (tface) + desc->init(); - face = &((const FontFaceRec_Typeface*)tface)->fFace; + SkScalerContext::Rec* newRec = - else + (SkScalerContext::Rec*)desc->addEntry(kRec_SkDescriptorTag, sizeof(rec), &rec); - face = get_default_font(); + + get_default_font(); + CreateTypeface_(gDefaultFont); - size_t size = sizeof(face); + newRec->fFontID = FontFaceChecksum(gDefaultFont.lfFaceName, GetFontStyle(gDefaultFont)); + desc->computeChecksum(); + - size += sizeof(uint32_t); + return SkFontHost::CreateScalerContext(desc); +} - if (buffer) { - uint8_t* buf = (uint8_t*)buffer; +/** Return the closest matching typeface given either an existing family - memcpy(buf, &face, sizeof(face)); + (specified by a typeface in that family) or by a familyName, and a - uint32_t cs = FontFaceChecksum(*face); + requested style. + 1) If familyFace is null, use famillyName. + 2) If famillyName is null, use familyFace. - memcpy(buf+sizeof(face), &cs, sizeof(cs)); + 3) If both are null, return the default font that best matches style - } + This MUST not return NULL. + */ - return size; -} +SkTypeface* SkFontHost::FindTypeface(const SkTypeface* familyFace, const char familyName[], SkTypeface::Style style) { + + SkAutoMutexAcquire ac(gFTMutex); -SkScalerContext* SkFontHost::CreateScalerContext(const SkDescriptor* desc) { - return SkNEW_ARGS(SkScalerContext_Windows, (desc)); -} +#ifndef CAN_USE_LOGFONT_NAME + familyName = NULL; + familyFace = NULL; -void SkFontHost::GetDescriptorKeyString(const SkDescriptor* desc, SkString* keyString) { +#endif - const LOGFONT** face = (const LOGFONT**)desc->findEntry(kTypeface_SkDescriptorTag, NULL); - LOGFONT*lf = (LOGFONT*)*face; - keyString->set(SK_FONTKEY); + // clip to legal style bits - if (lf) { + style = (SkTypeface::Style)(style & SkTypeface::kBoldItalic); - keyString->append(lf->lfFaceName); + - } + SkTypeface* tf = NULL; -} + if (NULL == familyFace && NULL == familyName) { + LOGFONT lf; + get_default_font(); -SkScalerContext* SkFontHost::CreateFallbackScalerContext(const SkScalerContext::Rec& rec) { + memcpy(&lf, &gDefaultFont, sizeof(LOGFONT)); - const LOGFONT* face = get_default_font(); + lf.lfWeight = (style & SkTypeface::kBold) != 0 ? FW_BOLD : FW_NORMAL ; + lf.lfItalic = ((style & SkTypeface::kItalic) != 0); + tf = CreateTypeface_(lf); - SkAutoDescriptor ad(sizeof(rec) + sizeof(face) + SkDescriptor::ComputeOverhead(2)); + } else { - SkDescriptor* desc = ad.getDesc(); +#ifdef CAN_USE_LOGFONT_NAME + LOGFONT lf; + if (NULL != familyFace) { - desc->init(); + uint32_t id = familyFace->uniqueID(); - desc->addEntry(kRec_SkDescriptorTag, sizeof(rec), &rec); + SkFaceRec* rec = find_ft_face(id); - desc->addEntry(kTypeface_SkDescriptorTag, sizeof(face), &face); + if (!rec) { - desc->computeChecksum(); + SkASSERT(false); + get_default_font(); + memcpy(&lf, &gDefaultFont, sizeof(LOGFONT)); - return SkFontHost::CreateScalerContext(desc); + } -} + else { + memcpy(&lf, &(rec->fFace), sizeof(LOGFONT)); + } -SkStream* SkFontHost::OpenDescriptorStream(const SkDescriptor* desc, const char keyString[]) { + } - SkASSERT(!"SkFontHost::OpenDescriptorStream unimplemented"); + else { - return NULL; + memset(&lf, 0, sizeof(LOGFONT)); -} + + lf.lfHeight = -11; // default + lf.lfQuality = PROOF_QUALITY; -uint32_t SkFontHost::TypefaceHash(const SkTypeface* face) { + lf.lfCharSet = DEFAULT_CHARSET; - + -// FontFaceRec_Typeface *ptypeface = dynamic_cast<FontFaceRec_Typeface*>(face); + _tcsncpy(lf.lfFaceName, familyName, LF_FACESIZE); - FontFaceRec_Typeface *ptypeface = (FontFaceRec_Typeface*)(face); + lf.lfFaceName[LF_FACESIZE-1] = '\0'; - SkASSERT(ptypeface); + } + + // use the style desired - return FontFaceChecksum(ptypeface->fFace); + lf.lfWeight = (style & SkTypeface::kBold) != 0 ? FW_BOLD : FW_NORMAL ; -} + lf.lfItalic = ((style & SkTypeface::kItalic) != 0); + tf = CreateTypeface_(lf); +#endif -bool SkFontHost::TypefaceEqual(const SkTypeface* facea, const SkTypeface* faceb) { + } - - FontFaceRec_Typeface *ptypefaceA = (FontFaceRec_Typeface*)facea; - SkASSERT(ptypefaceA); + if (NULL == tf) { + get_default_font(); + tf = CreateTypeface_(gDefaultFont); - FontFaceRec_Typeface *ptypefaceB = (FontFaceRec_Typeface*)faceb; + } - SkASSERT(ptypefaceB); + return tf; +} - if (_tcscmp(ptypefaceA->GetFontName(), ptypefaceB->GetFontName())) return false; - if (ptypefaceA->GetFontStyle() != ptypefaceB->GetFontStyle()) return false; +size_t SkFontHost::ShouldPurgeFontCache(size_t sizeAllocatedSoFar) { - if (ptypefaceA->GetFontSize() != ptypefaceB->GetFontSize()) return false; + if (sizeAllocatedSoFar > FONT_CACHE_MEMORY_BUDGET) + return sizeAllocatedSoFar - FONT_CACHE_MEMORY_BUDGET; + else - return true; + return 0; // nothing to do } -int SkFontHost::ComputeGammaFlag(const SkPaint& paint) - -{ +int SkFontHost::ComputeGammaFlag(const SkPaint& paint) { return 0; @@ -890,9 +1186,7 @@ int SkFontHost::ComputeGammaFlag(const SkPaint& paint) -void SkFontHost::GetGammaTables(const uint8_t* tables[2]) - -{ +void SkFontHost::GetGammaTables(const uint8_t* tables[2]) { tables[0] = NULL; // black gamma (e.g. exp=1.4) diff --git a/skia/ports/SkGlobals_global.cpp b/skia/ports/SkGlobals_global.cpp index f5f48ef..d87568b 100644 --- a/skia/ports/SkGlobals_global.cpp +++ b/skia/ports/SkGlobals_global.cpp @@ -1,6 +1,6 @@ /* libs/graphics/ports/SkGlobals_global.cpp ** -** Copyright 2006, Google Inc. +** Copyright 2006, The Android Open Source Project ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. diff --git a/skia/ports/SkImageDecoder_Factory.cpp b/skia/ports/SkImageDecoder_Factory.cpp index 67d4dcb..d5d7b3f 100644 --- a/skia/ports/SkImageDecoder_Factory.cpp +++ b/skia/ports/SkImageDecoder_Factory.cpp @@ -1,6 +1,6 @@ /* libs/graphics/ports/SkImageDecoder_Factory.cpp ** -** Copyright 2006, Google Inc. +** Copyright 2006, The Android Open Source Project ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. @@ -19,19 +19,12 @@ #include "SkMovie.h" #include "SkStream.h" -//#define USE_PV_FOR_JPEG - extern SkImageDecoder* SkImageDecoder_GIF_Factory(SkStream*); extern SkImageDecoder* SkImageDecoder_BMP_Factory(SkStream*); extern SkImageDecoder* SkImageDecoder_ICO_Factory(SkStream*); extern SkImageDecoder* SkImageDecoder_PNG_Factory(SkStream*); extern SkImageDecoder* SkImageDecoder_WBMP_Factory(SkStream*); -#ifdef USE_PV_FOR_JPEG - extern SkImageDecoder* SkImageDecoder_PVJPEG_Factory(SkStream*); -#else - extern SkImageDecoder* SkImageDecoder_JPEG_Factory(SkStream*); -#endif - +extern SkImageDecoder* SkImageDecoder_JPEG_Factory(SkStream*); typedef SkImageDecoder* (*SkImageDecoderFactoryProc)(SkStream*); @@ -46,12 +39,7 @@ static const CodecFormat gPairs[] = { { SkImageDecoder_ICO_Factory, SkImageDecoder::kICO_Format }, { SkImageDecoder_WBMP_Factory, SkImageDecoder::kWBMP_Format }, { SkImageDecoder_BMP_Factory, SkImageDecoder::kBMP_Format }, - // jpeg must be last, as it doesn't have a good sniffer yet -#ifdef USE_PV_FOR_JPEG - { SkImageDecoder_PVJPEG_Factory, SkImageDecoder::kJPEG_Format } -#else { SkImageDecoder_JPEG_Factory, SkImageDecoder::kJPEG_Format } -#endif }; SkImageDecoder* SkImageDecoder::Factory(SkStream* stream) { diff --git a/skia/ports/SkImageRef_ashmem.cpp b/skia/ports/SkImageRef_ashmem.cpp index ef5fc58..1bb65c4 100644 --- a/skia/ports/SkImageRef_ashmem.cpp +++ b/skia/ports/SkImageRef_ashmem.cpp @@ -37,7 +37,10 @@ SkImageRef_ashmem::SkImageRef_ashmem(SkStream* stream, SkImageRef_ashmem::~SkImageRef_ashmem() { fCT->safeUnref(); + this->closeFD(); +} +void SkImageRef_ashmem::closeFD() { if (-1 != fRec.fFD) { #ifdef DUMP_ASHMEM_LIFECYCLE SkDebugf("=== ashmem close %d\n", fRec.fFD); @@ -46,6 +49,7 @@ SkImageRef_ashmem::~SkImageRef_ashmem() { SkASSERT(fRec.fSize); munmap(fRec.fAddr, fRec.fSize); close(fRec.fFD); + fRec.fFD = -1; } } @@ -136,6 +140,7 @@ bool SkImageRef_ashmem::onDecode(SkImageDecoder* codec, SkStream* stream, ashmem_unpin_region(fRec.fFD, 0, 0); fRec.fPinned = false; } + this->closeFD(); return false; } } @@ -183,13 +188,16 @@ void* SkImageRef_ashmem::onLockPixels(SkColorTable** ct) { void SkImageRef_ashmem::onUnlockPixels() { this->INHERITED::onUnlockPixels(); - SkASSERT(-1 != fRec.fFD); - SkASSERT(fRec.fAddr); - SkASSERT(fRec.fPinned); - - ashmem_unpin_region(fRec.fFD, 0, 0); - fRec.fPinned = false; + if (-1 != fRec.fFD) { + SkASSERT(fRec.fAddr); + SkASSERT(fRec.fPinned); + + ashmem_unpin_region(fRec.fFD, 0, 0); + fRec.fPinned = false; + } + // we clear this with or without an error, since we've either closed or + // unpinned the region fBitmap.setPixels(NULL, NULL); } diff --git a/skia/ports/SkImageRef_ashmem.h b/skia/ports/SkImageRef_ashmem.h index 909baea..193a01d 100644 --- a/skia/ports/SkImageRef_ashmem.h +++ b/skia/ports/SkImageRef_ashmem.h @@ -24,6 +24,8 @@ protected: virtual void onUnlockPixels(); private: + void closeFD(); + SkColorTable* fCT; SkAshmemRec fRec; diff --git a/skia/ports/SkOSEvent_android.cpp b/skia/ports/SkOSEvent_android.cpp index 8e16440..59d6191 100644 --- a/skia/ports/SkOSEvent_android.cpp +++ b/skia/ports/SkOSEvent_android.cpp @@ -1,6 +1,6 @@ /* libs/graphics/ports/SkOSEvent_android.cpp ** -** Copyright 2006, Google Inc. +** Copyright 2006, The Android Open Source Project ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. diff --git a/skia/ports/SkOSEvent_dummy.cpp b/skia/ports/SkOSEvent_dummy.cpp index c83995e..f061b6e 100644 --- a/skia/ports/SkOSEvent_dummy.cpp +++ b/skia/ports/SkOSEvent_dummy.cpp @@ -1,6 +1,6 @@ /* libs/graphics/ports/SkOSEvent_dummy.cpp ** -** Copyright 2006, Google Inc. +** Copyright 2006, The Android Open Source Project ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. diff --git a/skia/ports/SkOSFile_stdio.cpp b/skia/ports/SkOSFile_stdio.cpp index 15ca451..7438f7b 100644 --- a/skia/ports/SkOSFile_stdio.cpp +++ b/skia/ports/SkOSFile_stdio.cpp @@ -1,6 +1,6 @@ /* libs/graphics/ports/SkOSFile_stdio.cpp ** -** Copyright 2006, Google Inc. +** Copyright 2006, The Android Open Source Project ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. diff --git a/skia/ports/SkThread_none.cpp b/skia/ports/SkThread_none.cpp index 3e66973..37a3834 100644 --- a/skia/ports/SkThread_none.cpp +++ b/skia/ports/SkThread_none.cpp @@ -1,6 +1,6 @@ /* libs/graphics/ports/SkThread_none.cpp ** -** Copyright 2006, Google Inc. +** Copyright 2006, The Android Open Source Project ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. diff --git a/skia/ports/SkThread_win.cpp b/skia/ports/SkThread_win.cpp index 791e4f4..d3f3e21 100644 --- a/skia/ports/SkThread_win.cpp +++ b/skia/ports/SkThread_win.cpp @@ -1,6 +1,6 @@ /* libs/graphics/ports/SkThread_none.cpp ** -** Copyright 2008, Google Inc. +** Copyright 2008, The Android Open Source Project ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. diff --git a/skia/ports/SkTime_Unix.cpp b/skia/ports/SkTime_Unix.cpp index 202fcb8..1bf3a76 100644 --- a/skia/ports/SkTime_Unix.cpp +++ b/skia/ports/SkTime_Unix.cpp @@ -1,6 +1,6 @@ /* libs/graphics/ports/SkTime_Unix.cpp ** -** Copyright 2006, Google Inc. +** Copyright 2006, The Android Open Source Project ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. diff --git a/skia/ports/SkXMLParser_empty.cpp b/skia/ports/SkXMLParser_empty.cpp index a316dba..9a27306 100644 --- a/skia/ports/SkXMLParser_empty.cpp +++ b/skia/ports/SkXMLParser_empty.cpp @@ -1,6 +1,6 @@ /* libs/graphics/ports/SkXMLParser_empty.cpp ** -** Copyright 2006, Google Inc. +** Copyright 2006, The Android Open Source Project ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. diff --git a/skia/ports/SkXMLParser_expat.cpp b/skia/ports/SkXMLParser_expat.cpp index 82a78db..7694d50 100644 --- a/skia/ports/SkXMLParser_expat.cpp +++ b/skia/ports/SkXMLParser_expat.cpp @@ -1,6 +1,6 @@ /* libs/graphics/ports/SkXMLParser_expat.cpp ** -** Copyright 2006, Google Inc. +** Copyright 2006, The Android Open Source Project ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. diff --git a/skia/ports/SkXMLParser_tinyxml.cpp b/skia/ports/SkXMLParser_tinyxml.cpp index c53587a..7f57b80 100644 --- a/skia/ports/SkXMLParser_tinyxml.cpp +++ b/skia/ports/SkXMLParser_tinyxml.cpp @@ -1,6 +1,6 @@ /* libs/graphics/ports/SkXMLParser_tinyxml.cpp ** -** Copyright 2006, Google Inc. +** Copyright 2006, The Android Open Source Project ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. diff --git a/skia/ports/SkXMLPullParser_expat.cpp b/skia/ports/SkXMLPullParser_expat.cpp index cd29a9e..949c7a9 100644 --- a/skia/ports/SkXMLPullParser_expat.cpp +++ b/skia/ports/SkXMLPullParser_expat.cpp @@ -1,6 +1,6 @@ /* libs/graphics/ports/SkXMLParser_expat.cpp ** -** Copyright 2006, Google Inc. +** Copyright 2006, The Android Open Source Project ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. diff --git a/skia/ports/sk_predefined_gamma.h b/skia/ports/sk_predefined_gamma.h new file mode 100644 index 0000000..0818b30 --- /dev/null +++ b/skia/ports/sk_predefined_gamma.h @@ -0,0 +1,44 @@ +#ifndef SK_PREDEFINED_GAMMA_H +#define SK_PREDEFINED_GAMMA_H + +// Gamma table for 1.4 +static const uint8_t gBlackGamma[] = { + 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x03, 0x03, 0x04, 0x04, 0x04, 0x05, + 0x05, 0x06, 0x06, 0x07, 0x07, 0x08, 0x08, 0x09, 0x09, 0x0A, 0x0A, 0x0B, 0x0C, 0x0C, 0x0D, 0x0D, + 0x0E, 0x0F, 0x0F, 0x10, 0x10, 0x11, 0x12, 0x12, 0x13, 0x14, 0x14, 0x15, 0x16, 0x16, 0x17, 0x18, + 0x19, 0x19, 0x1A, 0x1B, 0x1C, 0x1C, 0x1D, 0x1E, 0x1F, 0x1F, 0x20, 0x21, 0x22, 0x22, 0x23, 0x24, + 0x25, 0x26, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x31, + 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, + 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, + 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 0x60, + 0x61, 0x62, 0x63, 0x64, 0x65, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71, + 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7C, 0x7D, 0x7E, 0x7F, 0x80, 0x81, 0x82, 0x84, + 0x85, 0x86, 0x87, 0x88, 0x89, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, 0x91, 0x92, 0x93, 0x94, 0x95, 0x97, + 0x98, 0x99, 0x9A, 0x9B, 0x9D, 0x9E, 0x9F, 0xA0, 0xA1, 0xA3, 0xA4, 0xA5, 0xA6, 0xA8, 0xA9, 0xAA, + 0xAB, 0xAD, 0xAE, 0xAF, 0xB0, 0xB2, 0xB3, 0xB4, 0xB5, 0xB7, 0xB8, 0xB9, 0xBB, 0xBC, 0xBD, 0xBE, + 0xC0, 0xC1, 0xC2, 0xC4, 0xC5, 0xC6, 0xC8, 0xC9, 0xCA, 0xCB, 0xCD, 0xCE, 0xCF, 0xD1, 0xD2, 0xD3, + 0xD5, 0xD6, 0xD7, 0xD9, 0xDA, 0xDB, 0xDD, 0xDE, 0xDF, 0xE1, 0xE2, 0xE3, 0xE5, 0xE6, 0xE8, 0xE9, + 0xEA, 0xEC, 0xED, 0xEE, 0xF0, 0xF1, 0xF2, 0xF4, 0xF5, 0xF7, 0xF8, 0xF9, 0xFB, 0xFC, 0xFE, 0xFF, +}; + +// Gamma table for 0.714286 +static const uint8_t gWhiteGamma[] = { + 0x00, 0x05, 0x08, 0x0B, 0x0D, 0x0F, 0x12, 0x14, 0x16, 0x17, 0x19, 0x1B, 0x1D, 0x1E, 0x20, 0x22, + 0x23, 0x25, 0x26, 0x28, 0x29, 0x2B, 0x2C, 0x2E, 0x2F, 0x31, 0x32, 0x33, 0x35, 0x36, 0x37, 0x39, + 0x3A, 0x3B, 0x3C, 0x3E, 0x3F, 0x40, 0x41, 0x43, 0x44, 0x45, 0x46, 0x48, 0x49, 0x4A, 0x4B, 0x4C, + 0x4D, 0x4E, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, + 0x5F, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, + 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, + 0x7F, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, + 0x8E, 0x8F, 0x8F, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x97, 0x98, 0x99, 0x9A, 0x9B, + 0x9C, 0x9D, 0x9E, 0x9E, 0x9F, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, + 0xAA, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 0xAF, 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB4, 0xB5, 0xB6, + 0xB7, 0xB8, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBC, 0xBD, 0xBE, 0xBF, 0xC0, 0xC0, 0xC1, 0xC2, 0xC3, + 0xC4, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCC, 0xCD, 0xCE, 0xCF, 0xCF, + 0xD0, 0xD1, 0xD2, 0xD3, 0xD3, 0xD4, 0xD5, 0xD6, 0xD6, 0xD7, 0xD8, 0xD9, 0xD9, 0xDA, 0xDB, 0xDC, + 0xDC, 0xDD, 0xDE, 0xDF, 0xDF, 0xE0, 0xE1, 0xE2, 0xE2, 0xE3, 0xE4, 0xE5, 0xE5, 0xE6, 0xE7, 0xE8, + 0xE8, 0xE9, 0xEA, 0xEB, 0xEB, 0xEC, 0xED, 0xEE, 0xEE, 0xEF, 0xF0, 0xF1, 0xF1, 0xF2, 0xF3, 0xF3, + 0xF4, 0xF5, 0xF6, 0xF6, 0xF7, 0xF8, 0xF9, 0xF9, 0xFA, 0xFB, 0xFB, 0xFC, 0xFD, 0xFE, 0xFE, 0xFF, +}; + +#endif |