summaryrefslogtreecommitdiffstats
path: root/skia/ports
diff options
context:
space:
mode:
authorbrettw@google.com <brettw@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2008-12-12 21:01:41 +0000
committerbrettw@google.com <brettw@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2008-12-12 21:01:41 +0000
commit52e935d04c59135739c3a68fb6e19d313dc6d5ad (patch)
tree95f7ab178b045bef4456cbf92c6aa7e476becd99 /skia/ports
parent30fab79877b4bb067944b74d98346ac9bb6bfc7e (diff)
downloadchromium_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')
-rw-r--r--skia/ports/SkFontHost_FONTPATH.cpp2
-rw-r--r--skia/ports/SkFontHost_FreeType.cpp403
-rw-r--r--skia/ports/SkFontHost_android.cpp65
-rw-r--r--skia/ports/SkFontHost_gamma.cpp77
-rw-r--r--skia/ports/SkFontHost_linux.cpp604
-rw-r--r--skia/ports/SkFontHost_mac.cpp562
-rw-r--r--skia/ports/SkFontHost_none.cpp54
-rw-r--r--skia/ports/SkFontHost_win.cpp818
-rw-r--r--skia/ports/SkGlobals_global.cpp2
-rw-r--r--skia/ports/SkImageDecoder_Factory.cpp16
-rw-r--r--skia/ports/SkImageRef_ashmem.cpp20
-rw-r--r--skia/ports/SkImageRef_ashmem.h2
-rw-r--r--skia/ports/SkOSEvent_android.cpp2
-rw-r--r--skia/ports/SkOSEvent_dummy.cpp2
-rw-r--r--skia/ports/SkOSFile_stdio.cpp2
-rw-r--r--skia/ports/SkThread_none.cpp2
-rw-r--r--skia/ports/SkThread_win.cpp2
-rw-r--r--skia/ports/SkTime_Unix.cpp2
-rw-r--r--skia/ports/SkXMLParser_empty.cpp2
-rw-r--r--skia/ports/SkXMLParser_expat.cpp2
-rw-r--r--skia/ports/SkXMLParser_tinyxml.cpp2
-rw-r--r--skia/ports/SkXMLPullParser_expat.cpp2
-rw-r--r--skia/ports/sk_predefined_gamma.h44
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