aboutsummaryrefslogtreecommitdiffstats
path: root/libsgl/ports
diff options
context:
space:
mode:
authorThe Android Open Source Project <initial-contribution@android.com>2008-10-21 07:00:00 -0700
committerThe Android Open Source Project <initial-contribution@android.com>2008-10-21 07:00:00 -0700
commit262917823441f183fa67aa63b9c0ec4e52cce4c3 (patch)
tree34f0861c241478f95ebbfeb0ae58d7cc40016f5f /libsgl/ports
downloadexternal_skia-262917823441f183fa67aa63b9c0ec4e52cce4c3.zip
external_skia-262917823441f183fa67aa63b9c0ec4e52cce4c3.tar.gz
external_skia-262917823441f183fa67aa63b9c0ec4e52cce4c3.tar.bz2
Initial Contribution
Diffstat (limited to 'libsgl/ports')
-rw-r--r--libsgl/ports/SkFontHost_FONTPATH.cpp415
-rw-r--r--libsgl/ports/SkFontHost_FreeType.cpp826
-rw-r--r--libsgl/ports/SkFontHost_android.cpp633
-rw-r--r--libsgl/ports/SkFontHost_ascender.cpp211
-rw-r--r--libsgl/ports/SkFontHost_gamma.cpp118
-rw-r--r--libsgl/ports/SkFontHost_none.cpp82
-rw-r--r--libsgl/ports/SkFontHost_win.cpp454
-rw-r--r--libsgl/ports/SkGlobals_global.cpp28
-rw-r--r--libsgl/ports/SkImageDecoder_Factory.cpp124
-rw-r--r--libsgl/ports/SkImageRef_ashmem.cpp195
-rw-r--r--libsgl/ports/SkImageRef_ashmem.h33
-rw-r--r--libsgl/ports/SkOSEvent_android.cpp155
-rw-r--r--libsgl/ports/SkOSEvent_dummy.cpp28
-rw-r--r--libsgl/ports/SkOSFile_stdio.cpp106
-rw-r--r--libsgl/ports/SkThread_none.cpp49
-rw-r--r--libsgl/ports/SkThread_pthread.cpp90
-rw-r--r--libsgl/ports/SkThread_win.cpp64
-rw-r--r--libsgl/ports/SkTime_Unix.cpp50
-rw-r--r--libsgl/ports/SkXMLParser_empty.cpp36
-rw-r--r--libsgl/ports/SkXMLParser_expat.cpp149
-rw-r--r--libsgl/ports/SkXMLParser_tinyxml.cpp96
-rw-r--r--libsgl/ports/SkXMLPullParser_expat.cpp222
-rw-r--r--libsgl/ports/sk_predefined_gamma.h44
23 files changed, 4208 insertions, 0 deletions
diff --git a/libsgl/ports/SkFontHost_FONTPATH.cpp b/libsgl/ports/SkFontHost_FONTPATH.cpp
new file mode 100644
index 0000000..3cbccaf
--- /dev/null
+++ b/libsgl/ports/SkFontHost_FONTPATH.cpp
@@ -0,0 +1,415 @@
+/* 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 "SkString.h"
+#include "SkStream.h"
+#include <stdio.h>
+
+/* define this if we can use mmap() to access fonts from the filesystem */
+#define SK_CAN_USE_MMAP
+
+#ifndef SK_FONTPATH
+ #define SK_FONTPATH "the complete path for a font file"
+#endif
+
+struct FontFaceRec {
+ const char* fFileName;
+ uint8_t fFamilyIndex;
+ SkBool8 fBold;
+ SkBool8 fItalic;
+
+ static const FontFaceRec& FindFace(const FontFaceRec rec[], int count, int isBold, int isItalic);
+};
+
+struct FontFamilyRec {
+ const FontFaceRec* fFaces;
+ int fFaceCount;
+};
+
+const FontFaceRec& FontFaceRec::FindFace(const FontFaceRec rec[], int count, int isBold, int isItalic)
+{
+ SkASSERT(count > 0);
+
+ int i;
+
+ // look for an exact match
+ for (i = 0; i < count; i++) {
+ if (rec[i].fBold == isBold && rec[i].fItalic == isItalic)
+ return rec[i];
+ }
+ // look for a match in the bold field
+ for (i = 0; i < count; i++) {
+ if (rec[i].fBold == isBold)
+ return rec[i];
+ }
+ // look for a normal/regular face
+ for (i = 0; i < count; i++) {
+ if (!rec[i].fBold && !rec[i].fItalic)
+ return rec[i];
+ }
+ // give up
+ return rec[0];
+}
+
+enum {
+ DEFAULT_FAMILY_INDEX,
+
+ FAMILY_INDEX_COUNT
+};
+
+static const FontFaceRec gDefaultFaces[] = {
+ { SK_FONTPATH, DEFAULT_FAMILY_INDEX, 0, 0 }
+};
+
+// This table must be in the same order as the ..._FAMILY_INDEX enum specifies
+static const FontFamilyRec gFamilies[] = {
+ { gDefaultFaces, SK_ARRAY_COUNT(gDefaultFaces) }
+};
+
+#define DEFAULT_FAMILY_INDEX DEFAULT_FAMILY_INDEX
+#define DEFAULT_FAMILY_FACE_INDEX 0
+
+////////////////////////////////////////////////////////////////////////////////////////
+
+/* map common "web" font names to our font list */
+
+struct FontFamilyMatchRec {
+ const char* fLCName;
+ int fFamilyIndex;
+};
+
+/* This is a table of synonyms for collapsing font names
+ down to their pseudo-equivalents (i.e. in terms of fonts
+ we actually have.)
+ Keep this sorted by the first field so we can do a binary search.
+ If this gets big, we could switch to a hash...
+*/
+static const FontFamilyMatchRec gMatches[] = {
+#if 0
+ { "Ahem", Ahem_FAMILY_INDEX },
+ { "arial", SANS_FAMILY_INDEX },
+ { "courier", MONO_FAMILY_INDEX },
+ { "courier new", MONO_FAMILY_INDEX },
+ { "cursive", SERIF_FAMILY_INDEX },
+ { "fantasy", SERIF_FAMILY_INDEX },
+ { "georgia", SERIF_FAMILY_INDEX },
+ { "goudy", SERIF_FAMILY_INDEX },
+ { "helvetica", SANS_FAMILY_INDEX },
+ { "palatino", SERIF_FAMILY_INDEX },
+ { "tahoma", SANS_FAMILY_INDEX },
+ { "sans-serif", SANS_FAMILY_INDEX },
+ { "serif", SERIF_FAMILY_INDEX },
+ { "times", SERIF_FAMILY_INDEX },
+ { "times new roman", SERIF_FAMILY_INDEX },
+ { "verdana", SANS_FAMILY_INDEX }
+#endif
+};
+
+////////////////////////////////////////////////////////////////////////////////////////
+
+#include "SkTSearch.h"
+
+static bool contains_only_ascii(const char s[])
+{
+ for (;;)
+ {
+ int c = *s++;
+ if (c == 0)
+ break;
+ if ((c >> 7) != 0)
+ return false;
+ }
+ return true;
+}
+
+#define TRACE_FONT_NAME(code)
+//#define TRACE_FONT_NAME(code) code
+
+const FontFamilyRec* find_family_rec(const char target[])
+{
+ int index;
+
+ // If we're asked for a font name that contains non-ascii,
+ // 1) SkStrLCSearch can't handle it
+ // 2) All of our fonts are have ascii names, so...
+
+TRACE_FONT_NAME(printf("----------------- font request <%s>", target);)
+
+ if (contains_only_ascii(target))
+ {
+ // Search for the font by matching the entire name
+ index = SkStrLCSearch(&gMatches[0].fLCName, SK_ARRAY_COUNT(gMatches), target, sizeof(gMatches[0]));
+ if (index >= 0)
+ {
+ TRACE_FONT_NAME(printf(" found %d\n", index);)
+ return &gFamilies[gMatches[index].fFamilyIndex];
+ }
+ }
+
+ // Sniff for key words...
+
+#if 0
+ if (strstr(target, "sans") || strstr(target, "Sans"))
+ {
+ TRACE_FONT_NAME(printf(" found sans\n");)
+ return &gFamilies[SANS_FAMILY_INDEX];
+ }
+ if (strstr(target, "serif") || strstr(target, "Serif"))
+ {
+ TRACE_FONT_NAME(printf(" found serif\n");)
+ return &gFamilies[SERIF_FAMILY_INDEX];
+ }
+ if (strstr(target, "mono") || strstr(target, "Mono"))
+ {
+ TRACE_FONT_NAME(printf(" found mono\n");)
+ return &gFamilies[MONO_FAMILY_INDEX];
+ }
+#endif
+
+ TRACE_FONT_NAME(printf(" use default\n");)
+ // we give up, just give them the default font
+ return &gFamilies[DEFAULT_FAMILY_INDEX];
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////
+
+static const FontFaceRec* get_default_face()
+{
+ return &gFamilies[DEFAULT_FAMILY_INDEX].fFaces[DEFAULT_FAMILY_FACE_INDEX];
+}
+
+class FontFaceRec_Typeface : public SkTypeface {
+public:
+ FontFaceRec_Typeface(const FontFaceRec& face) : fFace(face)
+ {
+ int style = 0;
+ if (face.fBold)
+ style |= SkTypeface::kBold;
+ if (face.fItalic)
+ style |= SkTypeface::kItalic;
+ this->setStyle((SkTypeface::Style)style);
+ }
+
+ // This global const reference completely identifies the face
+ const FontFaceRec& fFace;
+};
+
+static const FontFaceRec* get_typeface_rec(const SkTypeface* face)
+{
+ const FontFaceRec_Typeface* f = (FontFaceRec_Typeface*)face;
+ return f ? &f->fFace : get_default_face();
+}
+
+static uint32_t ptr2uint32(const void* p)
+{
+ // cast so we avoid warnings on 64bit machines that a ptr difference
+ // which might be 64bits is being trucated from 64 to 32
+ return (uint32_t)((char*)p - (char*)0);
+}
+
+uint32_t SkFontHost::TypefaceHash(const SkTypeface* face)
+{
+ // just use our address as the hash value
+ return ptr2uint32(get_typeface_rec(face));
+}
+
+bool SkFontHost::TypefaceEqual(const SkTypeface* facea, const SkTypeface* faceb)
+{
+ return get_typeface_rec(facea) == get_typeface_rec(faceb);
+}
+
+SkTypeface* SkFontHost::CreateTypeface(const SkTypeface* familyFace, const char familyName[], SkTypeface::Style style)
+{
+ const FontFamilyRec* family;
+
+ if (familyFace)
+ family = &gFamilies[((FontFaceRec_Typeface*)familyFace)->fFace.fFamilyIndex];
+ else if (familyName)
+ family = find_family_rec(familyName);
+ else
+ family = &gFamilies[DEFAULT_FAMILY_INDEX];
+
+ const FontFaceRec& face = FontFaceRec::FindFace(family->fFaces, family->fFaceCount,
+ (style & SkTypeface::kBold) != 0,
+ (style & SkTypeface::kItalic) != 0);
+
+ // if we're returning our input parameter, no need to create a new instance
+ if (familyFace != NULL && &((FontFaceRec_Typeface*)familyFace)->fFace == &face)
+ {
+ familyFace->ref();
+ return (SkTypeface*)familyFace;
+ }
+ return SkNEW_ARGS(FontFaceRec_Typeface, (face));
+}
+
+uint32_t SkFontHost::FlattenTypeface(const SkTypeface* tface, void* buffer)
+{
+ const FontFaceRec* face;
+
+ if (tface)
+ face = &((const FontFaceRec_Typeface*)tface)->fFace;
+ else
+ face = get_default_face();
+
+ size_t size = sizeof(face);
+ if (buffer)
+ memcpy(buffer, &face, size);
+ return size;
+}
+
+void SkFontHost::GetDescriptorKeyString(const SkDescriptor* desc, SkString* key)
+{
+ key->set(SK_FONTPATH);
+}
+
+#ifdef SK_CAN_USE_MMAP
+#include <unistd.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <errno.h>
+
+class SkMMAPStream : public SkMemoryStream {
+public:
+ SkMMAPStream(const char filename[]);
+ virtual ~SkMMAPStream();
+
+ virtual void setMemory(const void* data, size_t length);
+private:
+ int fFildes;
+ void* fAddr;
+ size_t fSize;
+
+ void closeMMap();
+
+ typedef SkMemoryStream INHERITED;
+};
+
+SkMMAPStream::SkMMAPStream(const char filename[])
+{
+ fFildes = -1; // initialize to failure case
+
+ int fildes = open(filename, O_RDONLY);
+ if (fildes < 0)
+ {
+ SkDEBUGF(("---- failed to open(%s) for mmap stream error=%d\n", filename, errno));
+ return;
+ }
+
+ off_t size = lseek(fildes, 0, SEEK_END); // find the file size
+ if (size == -1)
+ {
+ SkDEBUGF(("---- failed to lseek(%s) for mmap stream error=%d\n", filename, errno));
+ close(fildes);
+ return;
+ }
+ (void)lseek(fildes, 0, SEEK_SET); // restore file offset to beginning
+
+ void* addr = mmap(NULL, size, PROT_READ, MAP_SHARED, fildes, 0);
+ if (MAP_FAILED == addr)
+ {
+ SkDEBUGF(("---- failed to mmap(%s) for mmap stream error=%d\n", filename, errno));
+ close(fildes);
+ return;
+ }
+
+ this->INHERITED::setMemory(addr, size);
+
+ fFildes = fildes;
+ fAddr = addr;
+ fSize = size;
+}
+
+SkMMAPStream::~SkMMAPStream()
+{
+ this->closeMMap();
+}
+
+void SkMMAPStream::setMemory(const void* data, size_t length)
+{
+ this->closeMMap();
+ this->INHERITED::setMemory(data, length);
+}
+
+void SkMMAPStream::closeMMap()
+{
+ if (fFildes >= 0)
+ {
+ munmap(fAddr, fSize);
+ close(fFildes);
+ fFildes = -1;
+ }
+}
+
+#endif
+
+SkStream* SkFontHost::OpenDescriptorStream(const SkDescriptor* desc, const char keyString[])
+{
+ // our key string IS our filename, so we can ignore desc
+ SkStream* strm;
+
+#ifdef SK_CAN_USE_MMAP
+ strm = new SkMMAPStream(keyString);
+ if (strm->getLength() > 0)
+ return strm;
+
+ // strm not valid
+ delete strm;
+ // fall through to FILEStream attempt
+#endif
+
+ strm = new SkFILEStream(keyString);
+ if (strm->getLength() > 0)
+ return strm;
+
+ // strm not valid
+ delete strm;
+ return NULL;
+}
+
+SkScalerContext* SkFontHost::CreateFallbackScalerContext(const SkScalerContext::Rec& rec)
+{
+ const FontFaceRec* face = get_default_face();
+
+ SkAutoDescriptor ad(sizeof(rec) + sizeof(face) + SkDescriptor::ComputeOverhead(2));
+ SkDescriptor* desc = ad.getDesc();
+
+ desc->init();
+ desc->addEntry(kRec_SkDescriptorTag, sizeof(rec), &rec);
+ desc->addEntry(kTypeface_SkDescriptorTag, sizeof(face), &face);
+ desc->computeChecksum();
+
+ return SkFontHost::CreateScalerContext(desc);
+}
+
+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)
+{
+ 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/libsgl/ports/SkFontHost_FreeType.cpp b/libsgl/ports/SkFontHost_FreeType.cpp
new file mode 100644
index 0000000..85f8d62
--- /dev/null
+++ b/libsgl/ports/SkFontHost_FreeType.cpp
@@ -0,0 +1,826 @@
+/* libs/graphics/ports/SkFontHost_FreeType.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 "SkScalerContext.h"
+#include "SkBitmap.h"
+#include "SkCanvas.h"
+#include "SkDescriptor.h"
+#include "SkFDot6.h"
+#include "SkFontHost.h"
+#include "SkMask.h"
+#include "SkStream.h"
+#include "SkString.h"
+#include "SkThread.h"
+#include "SkTemplates.h"
+
+#include <ft2build.h>
+#include FT_FREETYPE_H
+#include FT_OUTLINE_H
+#include FT_SIZES_H
+#ifdef FT_ADVANCES_H
+#include FT_ADVANCES_H
+#endif
+
+//#define ENABLE_GLYPH_SPEW // for tracing calls
+//#define DUMP_STRIKE_CREATION
+
+#ifdef SK_DEBUG
+ #define SkASSERT_CONTINUE(pred) \
+ do { \
+ if (!(pred)) \
+ SkDebugf("file %s:%d: assert failed '" #pred "'\n", __FILE__, __LINE__); \
+ } while (false)
+#else
+ #define SkASSERT_CONTINUE(pred)
+#endif
+
+//////////////////////////////////////////////////////////////////////////
+
+struct SkFaceRec;
+
+static SkMutex gFTMutex;
+static int gFTCount;
+static FT_Library gFTLibrary;
+static SkFaceRec* gFaceRecHead;
+
+/////////////////////////////////////////////////////////////////////////
+
+class SkScalerContext_FreeType : public SkScalerContext {
+public:
+ SkScalerContext_FreeType(const SkDescriptor* desc);
+ virtual ~SkScalerContext_FreeType();
+
+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 generateFontMetrics(SkPaint::FontMetrics* mx,
+ SkPaint::FontMetrics* my);
+
+private:
+ SkFaceRec* fFaceRec;
+ FT_Face fFace; // reference to shared face in gFaceRecHead
+ FT_Size fFTSize; // our own copy
+ SkFixed fScaleX, fScaleY;
+ FT_Matrix fMatrix22;
+ uint32_t fLoadGlyphFlags;
+
+ FT_Error setupSize();
+};
+
+///////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////
+
+#include "SkStream.h"
+
+struct SkFaceRec {
+ SkFaceRec* fNext;
+ FT_Face fFace;
+ FT_StreamRec fFTStream;
+ SkStream* fSkStream;
+ uint32_t fRefCnt;
+ uint32_t fFontID;
+
+ SkFaceRec(SkStream* strm, uint32_t fontID);
+ ~SkFaceRec() {
+ SkFontHost::CloseStream(fFontID, fSkStream);
+ }
+};
+
+extern "C" {
+ static unsigned long sk_stream_read(FT_Stream stream,
+ unsigned long offset,
+ unsigned char* buffer,
+ unsigned long count ) {
+ SkStream* str = (SkStream*)stream->descriptor.pointer;
+
+ if (count) {
+ if (!str->rewind()) {
+ return 0;
+ } else {
+ unsigned long ret;
+ if (offset) {
+ ret = str->read(NULL, offset);
+ if (ret != offset) {
+ return 0;
+ }
+ }
+ ret = str->read(buffer, count);
+ if (ret != count) {
+ return 0;
+ }
+ count = ret;
+ }
+ }
+ return count;
+ }
+
+ static void sk_stream_close( FT_Stream stream) {}
+}
+
+SkFaceRec::SkFaceRec(SkStream* strm, uint32_t fontID)
+ : fSkStream(strm), fFontID(fontID) {
+// SkDEBUGF(("SkFaceRec: opening %s (%p)\n", key.c_str(), strm));
+
+ 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) {
+ SkFaceRec* rec = gFaceRecHead;
+ while (rec) {
+ if (rec->fFontID == fontID) {
+ SkASSERT(rec->fFace);
+ rec->fRefCnt += 1;
+ return rec;
+ }
+ rec = rec->fNext;
+ }
+
+ SkStream* strm = SkFontHost::OpenStream(fontID);
+ if (NULL == strm) {
+ SkDEBUGF(("SkFontHost::OpenStream failed opening %x\n", fontID));
+ sk_throw();
+ return 0;
+ }
+
+ // this passes ownership of strm to the rec
+ rec = SkNEW_ARGS(SkFaceRec, (strm, fontID));
+
+ FT_Open_Args args;
+ memset(&args, 0, sizeof(args));
+ const void* memoryBase = strm->getMemoryBase();
+
+ 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 {
+//printf("fopen(%s)\n", keyString.c_str());
+ args.flags = FT_OPEN_STREAM;
+ args.stream = &rec->fFTStream;
+ }
+
+ FT_Error err = FT_Open_Face(gFTLibrary, &args, 0, &rec->fFace);
+
+ 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 {
+ SkASSERT(rec->fFace);
+ //fprintf(stderr, "Opened font '%s'\n", filename.c_str());
+ rec->fNext = gFaceRecHead;
+ gFaceRecHead = rec;
+ rec->fRefCnt = 1;
+ return rec;
+ }
+}
+
+static void unref_ft_face(FT_Face face) {
+ SkFaceRec* rec = gFaceRecHead;
+ SkFaceRec* prev = NULL;
+ while (rec) {
+ SkFaceRec* next = rec->fNext;
+ if (rec->fFace == face) {
+ if (--rec->fRefCnt == 0) {
+ if (prev) {
+ prev->fNext = next;
+ } else {
+ gFaceRecHead = next;
+ }
+ FT_Done_Face(face);
+ SkDELETE(rec);
+ }
+ return;
+ }
+ prev = rec;
+ rec = next;
+ }
+ SkASSERT("shouldn't get here, face not in list");
+}
+
+///////////////////////////////////////////////////////////////////////////
+
+SkScalerContext_FreeType::SkScalerContext_FreeType(const SkDescriptor* desc)
+ : SkScalerContext(desc), fFTSize(NULL) {
+ SkAutoMutexAcquire ac(gFTMutex);
+
+ FT_Error err;
+
+ if (gFTCount == 0) {
+ err = FT_Init_FreeType(&gFTLibrary);
+// SkDEBUGF(("FT_Init_FreeType returned %d\n", err));
+ SkASSERT(err == 0);
+ }
+ ++gFTCount;
+
+ // load the font file
+ fFaceRec = ref_ft_face(fRec.fFontID);
+ fFace = fFaceRec ? fFaceRec->fFace : NULL;
+
+ // compute our factors from the record
+
+ SkMatrix m;
+
+ fRec.getSingleMatrix(&m);
+
+#ifdef DUMP_STRIKE_CREATION
+ SkString keyString;
+ SkFontHost::GetDescriptorKeyString(desc, &keyString);
+ printf("========== strike [%g %g %g] [%g %g %g %g] hints %d format %d %s\n", SkScalarToFloat(fRec.fTextSize),
+ SkScalarToFloat(fRec.fPreScaleX), SkScalarToFloat(fRec.fPreSkewX),
+ SkScalarToFloat(fRec.fPost2x2[0][0]), SkScalarToFloat(fRec.fPost2x2[0][1]),
+ SkScalarToFloat(fRec.fPost2x2[1][0]), SkScalarToFloat(fRec.fPost2x2[1][1]),
+ fRec.fHints, fRec.fMaskFormat, keyString.c_str());
+#endif
+
+ // now compute our scale factors
+ SkScalar sx = m.getScaleX();
+ SkScalar sy = m.getScaleY();
+
+ 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);
+
+ SkScalar inv = SkScalarInvert(sx);
+
+ // flip the skew elements to go from our Y-down system to FreeType's
+ fMatrix22.xx = SkScalarToFixed(SkScalarMul(m.getScaleX(), inv));
+ fMatrix22.xy = -SkScalarToFixed(SkScalarMul(m.getSkewX(), inv));
+ fMatrix22.yx = -SkScalarToFixed(SkScalarMul(m.getSkewY(), inv));
+ fMatrix22.yy = SkScalarToFixed(SkScalarMul(m.getScaleY(), inv));
+ } else {
+ fMatrix22.xx = fMatrix22.yy = SK_Fixed1;
+ fMatrix22.xy = fMatrix22.yx = 0;
+ }
+
+ fScaleX = SkScalarToFixed(sx);
+ fScaleY = SkScalarToFixed(sy);
+
+ // compute the flags we send to Load_Glyph
+ {
+ uint32_t flags = FT_LOAD_DEFAULT;
+ uint32_t render_flags = FT_LOAD_TARGET_NORMAL;
+
+ // we force autohinting at the moment
+
+ switch (fRec.fHints) {
+ case kNo_Hints:
+ flags |= FT_LOAD_NO_HINTING;
+ break;
+ case kSubpixel_Hints:
+ flags |= FT_LOAD_FORCE_AUTOHINT;
+ render_flags = FT_LOAD_TARGET_LIGHT;
+ break;
+ case kNormal_Hints:
+ 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;
+ }
+
+ if (SkMask::kBW_Format == fRec.fMaskFormat)
+ render_flags = FT_LOAD_TARGET_MONO;
+ else if (SkMask::kLCD_Format == fRec.fMaskFormat)
+ render_flags = FT_LOAD_TARGET_LCD;
+
+ fLoadGlyphFlags = flags | render_flags;
+ }
+
+ // now create the FT_Size
+
+ {
+ FT_Error err;
+
+ err = FT_New_Size(fFace, &fFTSize);
+ if (err != 0) {
+ SkDEBUGF(("SkScalerContext_FreeType::FT_New_Size(%x): FT_Set_Char_Size(0x%x, 0x%x) returned 0x%x\n",
+ fFaceRec->fFontID, fScaleX, fScaleY, err));
+ fFace = NULL;
+ return;
+ }
+
+ err = FT_Activate_Size(fFTSize);
+ if (err != 0) {
+ SkDEBUGF(("SkScalerContext_FreeType::FT_Activate_Size(%x, 0x%x, 0x%x) returned 0x%x\n",
+ fFaceRec->fFontID, fScaleX, fScaleY, err));
+ fFTSize = NULL;
+ }
+
+ err = FT_Set_Char_Size( fFace,
+ SkFixedToFDot6(fScaleX), SkFixedToFDot6(fScaleY),
+ 72, 72);
+ if (err != 0) {
+ SkDEBUGF(("SkScalerContext_FreeType::FT_Set_Char_Size(%x, 0x%x, 0x%x) returned 0x%x\n",
+ fFaceRec->fFontID, fScaleX, fScaleY, err));
+ fFace = NULL;
+ return;
+ }
+
+ FT_Set_Transform( fFace, &fMatrix22, NULL);
+ }
+}
+
+SkScalerContext_FreeType::~SkScalerContext_FreeType() {
+ if (fFTSize != NULL) {
+ FT_Done_Size(fFTSize);
+ }
+
+ SkAutoMutexAcquire ac(gFTMutex);
+
+ if (fFace != NULL) {
+ unref_ft_face(fFace);
+ }
+ if (--gFTCount == 0) {
+// SkDEBUGF(("FT_Done_FreeType\n"));
+ FT_Done_FreeType(gFTLibrary);
+ SkDEBUGCODE(gFTLibrary = NULL;)
+ }
+}
+
+/* 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() {
+ if (SkFontHost::ResolveTypeface(fRec.fFontID) == NULL) {
+ return (FT_Error)-1;
+ }
+
+ FT_Error err = FT_Activate_Size(fFTSize);
+
+ if (err != 0) {
+ SkDEBUGF(("SkScalerContext_FreeType::FT_Activate_Size(%x, 0x%x, 0x%x) returned 0x%x\n",
+ fFaceRec->fFontID, fScaleX, fScaleY, err));
+ fFTSize = NULL;
+ } 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);
+ }
+ return err;
+}
+
+unsigned SkScalerContext_FreeType::generateGlyphCount() const {
+ return fFace->num_glyphs;
+}
+
+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) {
+ 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;
+ }
+}
+
+static void set_glyph_metrics_on_error(SkGlyph* glyph) {
+ glyph->fRsbDelta = 0;
+ glyph->fLsbDelta = 0;
+ glyph->fWidth = 0;
+ glyph->fHeight = 0;
+ glyph->fTop = 0;
+ glyph->fLeft = 0;
+ glyph->fAdvanceX = 0;
+ glyph->fAdvanceY = 0;
+}
+
+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) {
+ SkAutoMutexAcquire ac(gFTMutex);
+
+ glyph->fRsbDelta = 0;
+ glyph->fLsbDelta = 0;
+
+ FT_Error err;
+
+ if (this->setupSize()) {
+ goto ERROR;
+ }
+
+ err = FT_Load_Glyph( fFace, glyph->getGlyphID(fBaseGlyphCount), fLoadGlyphFlags );
+ 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:
+ set_glyph_metrics_on_error(glyph);
+ return;
+ }
+
+ 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) {
+ int dx = glyph->getSubXFixed() >> 10;
+ int dy = glyph->getSubYFixed() >> 10;
+ bbox.xMin += dx;
+ bbox.yMin += dy;
+ bbox.xMax += dx;
+ bbox.yMax += dy;
+ }
+
+ bbox.xMin &= ~63;
+ bbox.yMin &= ~63;
+ bbox.xMax = (bbox.xMax + 63) & ~63;
+ bbox.yMax = (bbox.yMax + 63) & ~63;
+
+ glyph->fWidth = SkToU16((bbox.xMax - bbox.xMin) >> 6);
+ glyph->fHeight = SkToU16((bbox.yMax - bbox.yMin) >> 6);
+ 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);
+ glyph->fTop = -SkToS16(fFace->glyph->bitmap_top);
+ glyph->fLeft = SkToS16(fFace->glyph->bitmap_left);
+ break;
+
+ default:
+ SkASSERT(!"unknown glyph format");
+ goto ERROR;
+ }
+
+ if (kNormal_Hints == fRec.fHints) {
+ glyph->fAdvanceX = SkFDot6ToFixed(fFace->glyph->advance.x);
+ glyph->fAdvanceY = -SkFDot6ToFixed(fFace->glyph->advance.y);
+ if (fRec.fFlags & kDevKernText_Flag) {
+ glyph->fRsbDelta = SkToS8(fFace->glyph->rsb_delta);
+ glyph->fLsbDelta = SkToS8(fFace->glyph->lsb_delta);
+ }
+ } else {
+ glyph->fAdvanceX = SkFixedMul(fMatrix22.xx, fFace->glyph->linearHoriAdvance);
+ glyph->fAdvanceY = -SkFixedMul(fMatrix22.yx, fFace->glyph->linearHoriAdvance);
+ }
+
+#ifdef ENABLE_GLYPH_SPEW
+ SkDEBUGF(("FT_Set_Char_Size(this:%p sx:%x sy:%x ", this, fScaleX, fScaleY));
+ SkDEBUGF(("Metrics(glyph:%d flags:0x%x) w:%d\n", glyph->getGlyphID(fBaseGlyphCount), fLoadGlyphFlags, glyph->fWidth));
+#endif
+}
+
+void SkScalerContext_FreeType::generateImage(const SkGlyph& glyph) {
+ SkAutoMutexAcquire ac(gFTMutex);
+
+ FT_Error err;
+
+ if (this->setupSize()) {
+ goto ERROR;
+ }
+
+ err = FT_Load_Glyph( fFace, glyph.getGlyphID(fBaseGlyphCount), fLoadGlyphFlags);
+ if (err != 0) {
+ SkDEBUGF(("SkScalerContext_FreeType::generateImage: FT_Load_Glyph(glyph:%d width:%d height:%d rb:%d flags:%d) returned 0x%x\n",
+ glyph.getGlyphID(fBaseGlyphCount), glyph.fWidth, glyph.fHeight, glyph.rowBytes(), fLoadGlyphFlags, err));
+ ERROR:
+ memset(glyph.fImage, 0, glyph.rowBytes() * glyph.fHeight);
+ return;
+ }
+
+ switch ( fFace->glyph->format ) {
+ 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) {
+ dx = glyph.getSubXFixed() >> 10;
+ dy = glyph.getSubYFixed() >> 10;
+ }
+ FT_Outline_Get_CBox(outline, &bbox);
+ /*
+ what we really want to do for subpixel is
+ offset(dx, dy)
+ compute_bounds
+ offset(bbox & !63)
+ but that is two calls to offset, so we do the following, which
+ achieves the same thing with only one offset call.
+ */
+ FT_Outline_Translate(outline, dx - ((bbox.xMin + dx) & ~63),
+ dy - ((bbox.yMin + dy) & ~63));
+
+ target.width = glyph.fWidth;
+ 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.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);
+
+ const uint8_t* src = (const uint8_t*)fFace->glyph->bitmap.buffer;
+ uint8_t* dst = (uint8_t*)glyph.fImage;
+ unsigned srcRowBytes = fFace->glyph->bitmap.pitch;
+ unsigned dstRowBytes = glyph.rowBytes();
+ unsigned minRowBytes = SkMin32(srcRowBytes, dstRowBytes);
+ unsigned extraRowBytes = dstRowBytes - minRowBytes;
+
+ 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;
+
+ default:
+ SkASSERT(!"unknown glyph format");
+ goto ERROR;
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+#define ft2sk(x) SkFixedToScalar((x) << 10)
+
+#if FREETYPE_MAJOR >= 2 && FREETYPE_MINOR >= 3
+ #define CONST_PARAM const
+#else // older freetype doesn't use const here
+ #define CONST_PARAM
+#endif
+
+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) {
+ 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) {
+ 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) {
+ SkPath* path = (SkPath*)ctx;
+ 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) {
+ SkAutoMutexAcquire ac(gFTMutex);
+
+ SkASSERT(&glyph && path);
+
+ if (this->setupSize()) {
+ path->reset();
+ return;
+ }
+
+ uint32_t flags = fLoadGlyphFlags;
+ flags |= FT_LOAD_NO_BITMAP; // ignore embedded bitmaps so we're sure to get the outline
+ flags &= ~FT_LOAD_RENDER; // don't scan convert (we just want the outline)
+
+ FT_Error err = FT_Load_Glyph( fFace, glyph.getGlyphID(fBaseGlyphCount), flags);
+
+ if (err != 0) {
+ SkDEBUGF(("SkScalerContext_FreeType::generatePath: FT_Load_Glyph(glyph:%d flags:%d) returned 0x%x\n",
+ glyph.getGlyphID(fBaseGlyphCount), flags, err));
+ path->reset();
+ return;
+ }
+
+ FT_Outline_Funcs funcs;
+
+ funcs.move_to = move_proc;
+ funcs.line_to = line_proc;
+ funcs.conic_to = quad_proc;
+ funcs.cubic_to = cubic_proc;
+ funcs.shift = 0;
+ funcs.delta = 0;
+
+ err = FT_Outline_Decompose(&fFace->glyph->outline, &funcs, path);
+
+ if (err != 0) {
+ SkDEBUGF(("SkScalerContext_FreeType::generatePath: FT_Load_Glyph(glyph:%d flags:%d) returned 0x%x\n",
+ glyph.getGlyphID(fBaseGlyphCount), flags, err));
+ path->reset();
+ return;
+ }
+
+ path->close();
+}
+
+static void map_y_to_pt(const FT_Matrix& mat, SkFixed y, SkPoint* pt) {
+ SkFixed x = SkFixedMul(mat.xy, y);
+ y = SkFixedMul(mat.yy, y);
+
+ pt->set(SkFixedToScalar(x), SkFixedToScalar(y));
+}
+
+void SkScalerContext_FreeType::generateFontMetrics(SkPaint::FontMetrics* mx,
+ SkPaint::FontMetrics* my) {
+ if (NULL == mx && NULL == my) {
+ return;
+ }
+
+ SkAutoMutexAcquire ac(gFTMutex);
+
+ if (this->setupSize()) {
+ if (mx) {
+ bzero(mx, sizeof(SkPaint::FontMetrics));
+ }
+ if (my) {
+ bzero(my, sizeof(SkPaint::FontMetrics));
+ }
+ return;
+ }
+
+ SkPoint pts[5];
+ SkFixed ys[5];
+ FT_Face face = fFace;
+ int upem = face->units_per_EM;
+ SkFixed scaleY = fScaleY;
+ SkFixed mxy = fMatrix22.xy;
+ SkFixed myy = fMatrix22.yy;
+
+ int leading = face->height - face->ascender + face->descender;
+ if (leading < 0) {
+ leading = 0;
+ }
+
+ ys[0] = -face->bbox.yMax;
+ ys[1] = -face->ascender;
+ ys[2] = -face->descender;
+ ys[3] = -face->bbox.yMin;
+ ys[4] = leading;
+
+ // convert upem-y values into scalar points
+ for (int i = 0; i < 5; 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) {
+ mx->fTop = pts[0].fX;
+ mx->fAscent = pts[1].fX;
+ mx->fDescent = pts[2].fX;
+ mx->fBottom = pts[3].fX;
+ mx->fLeading = pts[4].fX;
+ }
+ if (my) {
+ my->fTop = pts[0].fY;
+ my->fAscent = pts[1].fY;
+ my->fDescent = pts[2].fY;
+ my->fBottom = pts[3].fY;
+ my->fLeading = pts[4].fY;
+ }
+}
+
+////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////
+
+SkScalerContext* SkFontHost::CreateScalerContext(const SkDescriptor* desc) {
+ return SkNEW_ARGS(SkScalerContext_FreeType, (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) {
+ 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;
+ args.memory_size = stream->getLength();
+ } else {
+ memset(&streamRec, 0, sizeof(streamRec));
+ streamRec.size = stream->read(NULL, 0);
+ 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/libsgl/ports/SkFontHost_android.cpp b/libsgl/ports/SkFontHost_android.cpp
new file mode 100644
index 0000000..665c788
--- /dev/null
+++ b/libsgl/ports/SkFontHost_android.cpp
@@ -0,0 +1,633 @@
+/* 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 "SkPaint.h"
+#include "SkString.h"
+#include "SkStream.h"
+#include "SkThread.h"
+#include "SkTSearch.h"
+#include <stdio.h>
+
+#define FONT_CACHE_MEMORY_BUDGET (768 * 1024)
+
+#ifndef SK_FONT_FILE_PREFIX
+ #define SK_FONT_FILE_PREFIX "/fonts/"
+#endif
+
+SkTypeface::Style find_name_and_style(SkStream* stream, SkString* name);
+
+static void GetFullPathForSysFonts(SkString* full, const char name[])
+{
+ full->set(getenv("ANDROID_ROOT"));
+ 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 SkTypeface* find_typeface(const char name[], SkTypeface::Style style)
+{
+ NameFamilyPair* list = gNameList.begin();
+ int count = gNameList.count();
+
+ int index = SkStrLCSearch(&list[0].fName, count, name, sizeof(list[0]));
+
+ if (index >= 0) {
+ return find_best_face(list[index].fFamily, style);
+ }
+ return 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, SkTypeface* familyMember)
+ : SkTypeface(style, sk_atomic_inc(&gUniqueFontID) + 1)
+ {
+ fIsSysFont = sysFont;
+
+ SkAutoMutexAcquire ac(gFamilyMutex);
+
+ FamilyRec* rec = NULL;
+ if (familyMember) {
+ rec = find_family(familyMember);
+ SkASSERT(rec);
+ } else {
+ rec = SkNEW(FamilyRec);
+ }
+ rec->fFaces[style] = this;
+ }
+
+ 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; }
+
+ virtual SkStream* openStream() = 0;
+ virtual void closeStream(SkStream*) = 0;
+ virtual const char* getUniqueString() const = 0;
+
+private:
+ bool fIsSysFont;
+
+ typedef SkTypeface INHERITED;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+class StreamTypeface : public FamilyTypeface {
+public:
+ StreamTypeface(Style style, bool sysFont, SkTypeface* familyMember,
+ SkStream* stream)
+ : INHERITED(style, sysFont, familyMember)
+ {
+ 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, SkTypeface* familyMember,
+ const char path[])
+ : INHERITED(style, sysFont, familyMember)
+ {
+ SkString fullpath;
+
+ if (sysFont) {
+ GetFullPathForSysFonts(&fullpath, path);
+ path = fullpath.c_str();
+ }
+ 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)
+{
+ SkString fullpath;
+ GetFullPathForSysFonts(&fullpath, path);
+
+ SkMMAPStream stream(fullpath.c_str());
+ if (stream.getLength() > 0) {
+ *style = find_name_and_style(&stream, name);
+ return true;
+ }
+ else {
+ SkFILEStream stream(fullpath.c_str());
+ if (stream.getLength() > 0) {
+ *style = find_name_and_style(&stream, name);
+ return true;
+ }
+ }
+
+ SkDebugf("---- failed to open <%s> as a font\n", fullpath.c_str());
+ return false;
+}
+
+struct FontInitRec {
+ const char* fFileName;
+ const char* const* fNames; // null-terminated list
+};
+
+static const char* gSansNames[] = {
+ "sans-serif", "arial", "helvetica", "tahoma", "verdana", NULL
+};
+
+static const char* gSerifNames[] = {
+ "serif", "times", "times new roman", "palatino", "georgia", "baskerville",
+ "goudy", "fantasy", "cursive", "ITC Stone Serif", NULL
+};
+
+static const char* gMonoNames[] = {
+ "monospace", "courier", "courier new", "monaco", NULL
+};
+
+static const char* gFBNames[] = { NULL };
+
+/* Fonts must be grouped by family, with the first font in a family having the
+ list of names (even if that list is empty), and the following members having
+ null for the list. The names list must be NULL-terminated
+*/
+static const FontInitRec gSystemFonts[] = {
+ { "DroidSans.ttf", gSansNames },
+ { "DroidSans-Bold.ttf", NULL },
+ { "DroidSerif-Regular.ttf", gSerifNames },
+ { "DroidSerif-Bold.ttf", NULL },
+ { "DroidSerif-Italic.ttf", NULL },
+ { "DroidSerif-BoldItalic.ttf", NULL },
+ { "DroidSansMono.ttf", gMonoNames },
+ { "DroidSansFallback.ttf", gFBNames }
+};
+
+#define DEFAULT_NAMES gSansNames
+
+// 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;
+ }
+
+ const FontInitRec* rec = gSystemFonts;
+ SkTypeface* firstInFamily = NULL;
+
+ for (size_t i = 0; i < SK_ARRAY_COUNT(gSystemFonts); i++) {
+ // if we're the first in a new family, clear firstInFamily
+ if (rec[i].fNames != NULL) {
+ firstInFamily = NULL;
+ }
+
+ SkString name;
+ SkTypeface::Style style;
+
+ if (!get_name_and_style(rec[i].fFileName, &name, &style)) {
+ SkDebugf("------ can't load <%s> as a font\n", rec[i].fFileName);
+ continue;
+ }
+
+ SkTypeface* tf = SkNEW_ARGS(FileTypeface,
+ (style,
+ true, // system-font (cannot delete)
+ firstInFamily, // what family to join
+ rec[i].fFileName) // filename
+ );
+
+ if (rec[i].fNames != NULL) {
+ firstInFamily = tf;
+ const char* const* names = rec[i].fNames;
+
+ // record the fallback if this is it
+ if (names == gFBNames) {
+ gFallBackTypeface = tf;
+ }
+ // record the default family if this is it
+ if (names == DEFAULT_NAMES) {
+ gDefaultFamily = find_family(tf);
+ }
+ // add the names to map to this family
+ FamilyRec* family = find_family(tf);
+ while (*names) {
+ add_name(*names, family);
+ names += 1;
+ }
+ }
+
+ }
+
+ // 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
+ gDefaultNormal = find_best_face(gDefaultFamily, SkTypeface::kNormal);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+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)
+{
+ 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/libsgl/ports/SkFontHost_ascender.cpp b/libsgl/ports/SkFontHost_ascender.cpp
new file mode 100644
index 0000000..2148850
--- /dev/null
+++ b/libsgl/ports/SkFontHost_ascender.cpp
@@ -0,0 +1,211 @@
+#include "SkScalerContext.h"
+#include "SkBitmap.h"
+#include "SkCanvas.h"
+#include "SkDescriptor.h"
+#include "SkFDot6.h"
+#include "SkFontHost.h"
+#include "SkMask.h"
+#include "SkStream.h"
+#include "SkString.h"
+#include "SkThread.h"
+#include "SkTemplates.h"
+
+#include <acaapi.h>
+
+//////////////////////////////////////////////////////////////////////////
+
+#include "SkMMapStream.h"
+
+class SkScalerContext_Ascender : public SkScalerContext {
+public:
+ SkScalerContext_Ascender(const SkDescriptor* desc);
+ virtual ~SkScalerContext_Ascender();
+
+protected:
+ virtual unsigned generateGlyphCount() const;
+ virtual uint16_t generateCharToGlyph(SkUnichar uni);
+ 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);
+
+private:
+ aca_FontHandle fHandle;
+ void* fWorkspace;
+ void* fGlyphWorkspace;
+ SkStream* fFontStream;
+ SkStream* fHintStream;
+};
+
+///////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////
+
+SkScalerContext_Ascender::SkScalerContext_Ascender(const SkDescriptor* desc)
+ : SkScalerContext(desc)
+{
+ int size = aca_Get_FontHandleRec_Size();
+ fHandle = (aca_FontHandle)sk_malloc_throw(size);
+
+ // get the pointer to the font
+
+ fFontStream = new SkMMAPStream("/UcsGB2312-Hei-H.FDL");
+ fHintStream = new SkMMAPStream("/genv6-23.bin");
+
+ void* hints = sk_malloc_throw(fHintStream->getLength());
+ memcpy(hints, fHintStream->getMemoryBase(), fHintStream->getLength());
+
+ aca_Create_Font_Handle(fHandle,
+ (void*)fFontStream->getMemoryBase(), fFontStream->getLength(),
+ "fred",
+ hints, fHintStream->getLength());
+
+ // compute our factors from the record
+
+ SkMatrix m;
+
+ fRec.getSingleMatrix(&m);
+
+ // now compute our scale factors
+ SkScalar sx = m.getScaleX();
+ SkScalar sy = m.getScaleY();
+
+ int ppemX = SkScalarRound(sx);
+ int ppemY = SkScalarRound(sy);
+
+ size = aca_Find_Font_Memory_Required(fHandle, ppemX, ppemY);
+ size *= 8; // Jeff suggests this :)
+ fWorkspace = sk_malloc_throw(size);
+ aca_Set_Font_Memory(fHandle, (uint8_t*)fWorkspace, size);
+
+ aca_GlyphAttribsRec rec;
+
+ memset(&rec, 0, sizeof(rec));
+ rec.xSize = ppemX;
+ rec.ySize = ppemY;
+ rec.doAdjust = true;
+ rec.doExceptions = true;
+ rec.doGlyphHints = true;
+ rec.doInterpolate = true;
+ rec.grayMode = 2;
+ aca_Set_Font_Attributes(fHandle, &rec, &size);
+
+ fGlyphWorkspace = sk_malloc_throw(size);
+ aca_Set_Glyph_Memory(fHandle, fGlyphWorkspace);
+}
+
+SkScalerContext_Ascender::~SkScalerContext_Ascender()
+{
+ delete fHintStream;
+ delete fFontStream;
+ sk_free(fGlyphWorkspace);
+ sk_free(fWorkspace);
+ sk_free(fHandle);
+}
+
+unsigned SkScalerContext_Ascender::generateGlyphCount() const
+{
+ return 1000;
+}
+
+uint16_t SkScalerContext_Ascender::generateCharToGlyph(SkUnichar uni)
+{
+ return (uint16_t)(uni & 0xFFFF);
+}
+
+void SkScalerContext_Ascender::generateMetrics(SkGlyph* glyph)
+{
+ glyph->fRsbDelta = 0;
+ glyph->fLsbDelta = 0;
+
+ aca_GlyphImageRec rec;
+ aca_Vector topLeft;
+
+ int adv = aca_Get_Adv_Width(fHandle, glyph->getGlyphID());
+ if (aca_GLYPH_NOT_PRESENT == adv)
+ goto ERROR;
+
+ aca_Rasterize(glyph->getGlyphID(), fHandle, &rec, &topLeft);
+
+ if (false) // error
+ {
+ERROR:
+ glyph->fWidth = 0;
+ glyph->fHeight = 0;
+ glyph->fTop = 0;
+ glyph->fLeft = 0;
+ glyph->fAdvanceX = 0;
+ glyph->fAdvanceY = 0;
+ return;
+ }
+
+ glyph->fWidth = rec.width;
+ glyph->fHeight = rec.rows;
+ glyph->fRowBytes = rec.width;
+ glyph->fTop = -topLeft.y;
+ glyph->fLeft = topLeft.x;
+ glyph->fAdvanceX = SkIntToFixed(adv);
+ glyph->fAdvanceY = SkIntToFixed(0);
+}
+
+void SkScalerContext_Ascender::generateImage(const SkGlyph& glyph)
+{
+ aca_GlyphImageRec rec;
+ aca_Vector topLeft;
+
+ aca_Rasterize(glyph.getGlyphID(), fHandle, &rec, &topLeft);
+
+ const uint8_t* src = (const uint8_t*)rec.buffer;
+ uint8_t* dst = (uint8_t*)glyph.fImage;
+ int height = glyph.fHeight;
+
+ src += rec.y0 * rec.pitch + rec.x0;
+ while (--height >= 0)
+ {
+ memcpy(dst, src, glyph.fWidth);
+ src += rec.pitch;
+ dst += glyph.fRowBytes;
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+void SkScalerContext_Ascender::generatePath(const SkGlyph& glyph, SkPath* path)
+{
+ SkRect r;
+
+ r.set(0, 0, SkIntToScalar(4), SkIntToScalar(4));
+ path->reset();
+ path->addRect(r);
+}
+
+void SkScalerContext_Ascender::generateFontMetrics(SkPaint::FontMetrics* mx, SkPaint::FontMetrics* my)
+{
+ if (NULL == mx && NULL == my)
+ return;
+
+ if (mx)
+ {
+ mx->fTop = SkIntToScalar(-16);
+ mx->fAscent = SkIntToScalar(-16);
+ mx->fDescent = SkIntToScalar(4);
+ mx->fBottom = SkIntToScalar(4);
+ mx->fLeading = 0;
+ }
+ if (my)
+ {
+ my->fTop = SkIntToScalar(-16);
+ my->fAscent = SkIntToScalar(-16);
+ my->fDescent = SkIntToScalar(4);
+ my->fBottom = SkIntToScalar(4);
+ my->fLeading = 0;
+ }
+}
+
+////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////
+
+SkScalerContext* SkFontHost::CreateScalerContext(const SkDescriptor* desc)
+{
+ return SkNEW_ARGS(SkScalerContext_Ascender, (desc));
+}
+
diff --git a/libsgl/ports/SkFontHost_gamma.cpp b/libsgl/ports/SkFontHost_gamma.cpp
new file mode 100644
index 0000000..0b95bce
--- /dev/null
+++ b/libsgl/ports/SkFontHost_gamma.cpp
@@ -0,0 +1,118 @@
+#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);
+ for (int i = 0; i < 256; i++)
+ {
+ float x = i / 255.f;
+ // printf(" %d %g", i, x);
+ x = powf(x, ee);
+ // printf(" %g", x);
+ int xx = SkScalarRound(SkFloatToScalar(x * 255));
+ // printf(" %d\n", xx);
+ table[i] = SkToU8(xx);
+ }
+}
+
+#ifdef DUMP_GAMMA_TABLES
+
+#include "SkString.h"
+
+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])
+{
+#ifndef USE_PREDEFINED_GAMMA_TABLES
+ if (!gGammaIsBuilt)
+ {
+ 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)
+{
+ if (paint.getShader() == NULL)
+ {
+ SkColor c = paint.getColor();
+ int r = SkColorGetR(c);
+ int g = SkColorGetG(c);
+ int b = SkColorGetB(c);
+ int luminance = (r * 2 + g * 5 + b) >> 3;
+
+ if (luminance <= BLACK_GAMMA_THRESHOLD)
+ {
+ // printf("------ black gamma for [%d %d %d]\n", r, g, b);
+ return SkScalerContext::kGammaForBlack_Flag;
+ }
+ if (luminance >= WHITE_GAMMA_THRESHOLD)
+ {
+ // printf("------ white gamma for [%d %d %d]\n", r, g, b);
+ return SkScalerContext::kGammaForWhite_Flag;
+ }
+ }
+ return 0;
+}
+
diff --git a/libsgl/ports/SkFontHost_none.cpp b/libsgl/ports/SkFontHost_none.cpp
new file mode 100644
index 0000000..b45cf16
--- /dev/null
+++ b/libsgl/ports/SkFontHost_none.cpp
@@ -0,0 +1,82 @@
+/* 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.
+** 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"
+
+SkTypeface* SkFontHost::FindTypeface(const SkTypeface* familyFace,
+ const char famillyName[],
+ SkTypeface::Style style) {
+ SkASSERT(!"SkFontHost::FindTypeface unimplemented");
+ return NULL;
+}
+
+SkTypeface* SkFontHost::ResolveTypeface(uint32_t uniqueID) {
+ SkASSERT(!"SkFontHost::ResolveTypeface unimplemented");
+ return NULL;
+}
+
+SkStream* SkFontHost::OpenStream(uint32_t uniqueID) {
+ SkASSERT(!"SkFontHost::OpenStream unimplemented");
+ return NULL;
+}
+
+void SkFontHost::CloseStream(uint32_t uniqueID, SkStream*) {
+ SkASSERT(!"SkFontHost::CloseStream unimplemented");
+}
+
+SkTypeface* SkFontHost::CreateTypeface(SkStream*) {
+ SkASSERT(!"SkFontHost::CreateTypeface unimplemented");
+ return NULL;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+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&) {
+ SkASSERT(!"SkFontHost::CreateFallbackScalerContext unimplemented");
+ return NULL;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+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) {
+ 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/libsgl/ports/SkFontHost_win.cpp b/libsgl/ports/SkFontHost_win.cpp
new file mode 100644
index 0000000..d8c2b12
--- /dev/null
+++ b/libsgl/ports/SkFontHost_win.cpp
@@ -0,0 +1,454 @@
+/* libs/graphics/ports/SkFontHost_win.cpp
+**
+** Copyright 2006, The Android Open Source Project
+**
+*/
+
+#include "SkString.h"
+//#include "SkStream.h"
+
+#include "SkFontHost.h"
+#include "SkDescriptor.h"
+#include "SkThread.h"
+
+#ifdef WIN32
+#include "windows.h"
+#include "tchar.h"
+
+static SkMutex gFTMutex;
+
+static LOGFONT gDefaultFont;
+
+static const uint16_t BUFFERSIZE = (16384 - 32);
+static uint8_t glyphbuf[BUFFERSIZE];
+
+#ifndef SK_FONTKEY
+ #define SK_FONTKEY "Windows Font Key"
+#endif
+
+inline FIXED SkFixedToFIXED(SkFixed x) {
+ return *(FIXED*)(&x);
+}
+
+class FontFaceRec_Typeface : public SkTypeface {
+public:
+#if 0
+ FontFaceRec_Typeface(const LOGFONT& face) : fFace(face)
+ {
+ int style = 0;
+ if (face.lfWeight == FW_SEMIBOLD || face.lfWeight == FW_DEMIBOLD || face.lfWeight == FW_BOLD)
+ style |= SkTypeface::kBold;
+ if (face.lfItalic)
+ style |= SkTypeface::kItalic;
+ this->setStyle((SkTypeface::Style)style);
+ }
+#endif
+ ~FontFaceRec_Typeface() {};
+
+ TCHAR* GetFontName() { return fFace.lfFaceName; }
+
+ SkTypeface::Style GetFontStyle() {
+ int style = SkTypeface::kNormal;
+ if (fFace.lfWeight == FW_SEMIBOLD || fFace.lfWeight == FW_DEMIBOLD || fFace.lfWeight == FW_BOLD)
+ style |= SkTypeface::kBold;
+ if (fFace.lfItalic)
+ style |= SkTypeface::kItalic;
+
+ return (SkTypeface::Style)style;
+ }
+
+ long GetFontSize() { return fFace.lfHeight; }
+
+ LOGFONT fFace;
+};
+
+
+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
+
+ NONCLIENTMETRICS ncm;
+ ncm.cbSize = sizeof(NONCLIENTMETRICS);
+ SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, 0);
+
+ memcpy(&gDefaultFont, &(ncm.lfMessageFont), sizeof(LOGFONT));
+
+ return &gDefaultFont;
+}
+
+static uint32_t FontFaceChecksum(const LOGFONT& face)
+{
+ uint32_t cs = 0;
+ uint32_t bytesize = sizeof(LOGFONT);
+ bytesize >>= 2;
+ uint32_t *p32 = (uint32_t*)&face;
+
+ while (bytesize) {
+ bytesize --;
+ cs ^= *p32;
+ p32 ++;
+ }
+
+ return cs;
+}
+
+class SkScalerContext_Windows : public SkScalerContext {
+public:
+ SkScalerContext_Windows(const SkDescriptor* desc);
+ virtual ~SkScalerContext_Windows();
+
+protected:
+ virtual unsigned generateGlyphCount() const;
+ virtual uint16_t generateCharToGlyph(SkUnichar uni);
+ 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);
+
+private:
+ LOGFONT* plf;
+ MAT2 mat22;
+};
+
+SkScalerContext_Windows::SkScalerContext_Windows(const SkDescriptor* desc)
+ : SkScalerContext(desc), plf(NULL)
+{
+ SkAutoMutexAcquire ac(gFTMutex);
+
+ const LOGFONT** face = (const LOGFONT**)desc->findEntry(kTypeface_SkDescriptorTag, NULL);
+ plf = (LOGFONT*)*face;
+ SkASSERT(plf);
+
+ mat22.eM11 = SkFixedToFIXED(fRec.fPost2x2[0][0]);
+ mat22.eM12 = SkFixedToFIXED(-fRec.fPost2x2[0][1]);
+ mat22.eM21 = SkFixedToFIXED(fRec.fPost2x2[1][0]);
+ mat22.eM22 = SkFixedToFIXED(-fRec.fPost2x2[1][1]);
+}
+
+SkScalerContext_Windows::~SkScalerContext_Windows() {
+}
+
+unsigned SkScalerContext_Windows::generateGlyphCount() const {
+ return 0xFFFF;
+// return fFace->num_glyphs;
+}
+
+uint16_t SkScalerContext_Windows::generateCharToGlyph(SkUnichar uni) {
+
+ // let's just use the uni as index on Windows
+ return SkToU16(uni);
+}
+
+void SkScalerContext_Windows::generateMetrics(SkGlyph* glyph) {
+
+ HDC ddc = ::CreateCompatibleDC(NULL);
+ SetBkMode(ddc, TRANSPARENT);
+
+ SkASSERT(plf);
+ plf->lfHeight = -SkFixedFloor(fRec.fTextSize);
+
+ HFONT font = CreateFontIndirect(plf);
+ HFONT oldfont = (HFONT)SelectObject(ddc, font);
+
+ GLYPHMETRICS gm;
+ memset(&gm, 0, sizeof(gm));
+
+ glyph->fRsbDelta = 0;
+ glyph->fLsbDelta = 0;
+
+ // 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);
+
+ if (GDI_ERROR != ret) {
+ if (ret == 0) {
+ // for white space, ret is zero and gmBlackBoxX, gmBlackBoxY are 1 incorrectly!
+ gm.gmBlackBoxX = gm.gmBlackBoxY = 0;
+ }
+ glyph->fWidth = gm.gmBlackBoxX;
+ glyph->fHeight = gm.gmBlackBoxY;
+ glyph->fTop = gm.gmptGlyphOrigin.y - gm.gmBlackBoxY;
+ glyph->fLeft = gm.gmptGlyphOrigin.x;
+ glyph->fAdvanceX = SkIntToFixed(gm.gmCellIncX);
+ glyph->fAdvanceY = -SkIntToFixed(gm.gmCellIncY);
+ }
+
+ ::SelectObject(ddc, oldfont);
+ ::DeleteObject(font);
+ ::DeleteDC(ddc);
+}
+
+void SkScalerContext_Windows::generateImage(const SkGlyph& glyph) {
+
+ SkAutoMutexAcquire ac(gFTMutex);
+
+ SkASSERT(plf);
+
+ HDC ddc = ::CreateCompatibleDC(NULL);
+ SetBkMode(ddc, TRANSPARENT);
+
+ plf->lfHeight = -SkFixedFloor(fRec.fTextSize);
+
+ HFONT font = CreateFontIndirect(plf);
+ HFONT oldfont = (HFONT)SelectObject(ddc, font);
+
+ GLYPHMETRICS gm;
+ memset(&gm, 0, sizeof(gm));
+
+ uint32_t total_size = GetGlyphOutlineW(ddc, glyph.f_GlyphID, GGO_GRAY8_BITMAP, &gm, 0, NULL, &mat22);
+ if (GDI_ERROR != total_size && total_size > 0) {
+ uint8_t *pBuff = new uint8_t[total_size];
+ if (NULL != pBuff) {
+ total_size = GetGlyphOutlineW(ddc, glyph.f_GlyphID, GGO_GRAY8_BITMAP, &gm, total_size, pBuff, &mat22);
+
+ SkASSERT(total_size != GDI_ERROR);
+
+ uint8_t* dst = (uint8_t*)glyph.fImage;
+ uint32_t pitch = (gm.gmBlackBoxX + 3) & ~0x3;
+
+ 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++) {
+ if (*src > 63) {
+ *dst = 0xFF;
+ }
+ else {
+ *dst = *src << 2; // scale to 0-255
+ }
+ dst++;
+ src++;
+ }
+ }
+
+ delete[] pBuff;
+ }
+ }
+
+ SkASSERT(GDI_ERROR != total_size && total_size >= 0);
+
+ ::SelectObject(ddc, oldfont);
+ ::DeleteObject(font);
+ ::DeleteDC(ddc);
+}
+
+void SkScalerContext_Windows::generatePath(const SkGlyph& glyph, SkPath* path) {
+
+ SkAutoMutexAcquire ac(gFTMutex);
+
+ SkASSERT(&glyph && path);
+
+ SkASSERT(plf);
+
+ path->reset();
+
+ HDC ddc = ::CreateCompatibleDC(NULL);
+ SetBkMode(ddc, TRANSPARENT);
+
+ plf->lfHeight = -SkFixedFloor(fRec.fTextSize);
+
+ HFONT font = CreateFontIndirect(plf);
+ HFONT oldfont = (HFONT)SelectObject(ddc, font);
+
+ GLYPHMETRICS gm;
+
+ 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));
+
+ 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));
+ }
+ }
+
+ if (pc->wType == TT_PRIM_QSPLINE) {
+ for (uint16_t u = 0; u < pc->cpfx - 1; u++) { // Walk through points in spline
+ POINTFX pnt_b = pc->apfx[u]; // B is always the current point
+ POINTFX pnt_c = pc->apfx[u+1];
+
+ if (u < pc->cpfx - 2) { // If not on last spline, compute C
+ pnt_c.x = SkFixedToFIXED(SkFixedAve(*(SkFixed*)(&pnt_b.x), *(SkFixed*)(&pnt_c.x)));
+ pnt_c.y = SkFixedToFIXED(SkFixedAve(*(SkFixed*)(&pnt_b.y), *(SkFixed*)(&pnt_c.y)));
+ }
+
+ path->quadTo(*(SkFixed*)(&pnt_b.x), *(SkFixed*)(&pnt_b.y), *(SkFixed*)(&pnt_c.x), *(SkFixed*)(&pnt_c.y));
+ }
+ }
+ cur_poly += sizeof(uint16_t) * 2 + sizeof(POINTFX) * pc->cpfx;
+ }
+ cur_glyph += th->cb;
+ }
+ }
+ else {
+ SkASSERT(false);
+ }
+
+ path->close();
+
+ ::SelectObject(ddc, oldfont);
+ ::DeleteObject(font);
+ ::DeleteDC(ddc);
+}
+
+
+// Note: not sure this is the correct implementation
+void SkScalerContext_Windows::generateLineHeight(SkPoint* ascent, SkPoint* descent) {
+
+ 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) {
+ if (ascent)
+ ascent->iset(0, otm.otmAscent);
+ if (descent)
+ descent->iset(0, otm.otmDescent);
+ }
+
+ ::SelectObject(ddc, oldfont);
+ ::DeleteObject(font);
+ ::DeleteDC(ddc);
+
+ return;
+}
+
+SkTypeface* SkFontHost::CreateTypeface( const SkTypeface* familyFace, const char familyName[], SkTypeface::Style style) {
+
+ FontFaceRec_Typeface* ptypeface = new FontFaceRec_Typeface;
+
+ if (NULL == ptypeface) {
+ SkASSERT(false);
+ return NULL;
+ }
+
+ memset(&ptypeface->fFace, 0, sizeof(LOGFONT));
+
+ // default
+ ptypeface->fFace.lfHeight = -11; // default
+ ptypeface->fFace.lfWeight = (style & SkTypeface::kBold) != 0 ? FW_BOLD : FW_NORMAL ;
+ ptypeface->fFace.lfItalic = ((style & SkTypeface::kItalic) != 0);
+ ptypeface->fFace.lfQuality = PROOF_QUALITY;
+
+ _tcscpy(ptypeface->fFace.lfFaceName, familyName);
+
+
+ return ptypeface;
+}
+
+uint32_t SkFontHost::FlattenTypeface(const SkTypeface* tface, void* buffer) {
+ const LOGFONT* face;
+
+ if (tface)
+ face = &((const FontFaceRec_Typeface*)tface)->fFace;
+ else
+ face = get_default_font();
+
+ size_t size = sizeof(face);
+
+ size += sizeof(uint32_t);
+
+ if (buffer) {
+ uint8_t* buf = (uint8_t*)buffer;
+ memcpy(buf, &face, sizeof(face));
+ uint32_t cs = FontFaceChecksum(*face);
+
+ memcpy(buf+sizeof(face), &cs, sizeof(cs));
+ }
+
+ return size;
+}
+
+SkScalerContext* SkFontHost::CreateScalerContext(const SkDescriptor* desc) {
+ return SkNEW_ARGS(SkScalerContext_Windows, (desc));
+}
+
+void SkFontHost::GetDescriptorKeyString(const SkDescriptor* desc, SkString* keyString) {
+ const LOGFONT** face = (const LOGFONT**)desc->findEntry(kTypeface_SkDescriptorTag, NULL);
+ LOGFONT*lf = (LOGFONT*)*face;
+ keyString->set(SK_FONTKEY);
+ if (lf) {
+ keyString->append(lf->lfFaceName);
+ }
+}
+
+SkScalerContext* SkFontHost::CreateFallbackScalerContext(const SkScalerContext::Rec& rec) {
+ const LOGFONT* face = get_default_font();
+
+ SkAutoDescriptor ad(sizeof(rec) + sizeof(face) + SkDescriptor::ComputeOverhead(2));
+ SkDescriptor* desc = ad.getDesc();
+
+ desc->init();
+ desc->addEntry(kRec_SkDescriptorTag, sizeof(rec), &rec);
+ desc->addEntry(kTypeface_SkDescriptorTag, sizeof(face), &face);
+ desc->computeChecksum();
+
+ return SkFontHost::CreateScalerContext(desc);
+}
+
+SkStream* SkFontHost::OpenDescriptorStream(const SkDescriptor* desc, const char keyString[]) {
+ SkASSERT(!"SkFontHost::OpenDescriptorStream unimplemented");
+ return NULL;
+}
+
+uint32_t SkFontHost::TypefaceHash(const SkTypeface* face) {
+
+// FontFaceRec_Typeface *ptypeface = dynamic_cast<FontFaceRec_Typeface*>(face);
+ FontFaceRec_Typeface *ptypeface = (FontFaceRec_Typeface*)(face);
+ SkASSERT(ptypeface);
+
+ return FontFaceChecksum(ptypeface->fFace);
+}
+
+bool SkFontHost::TypefaceEqual(const SkTypeface* facea, const SkTypeface* faceb) {
+
+ FontFaceRec_Typeface *ptypefaceA = (FontFaceRec_Typeface*)facea;
+ SkASSERT(ptypefaceA);
+
+ FontFaceRec_Typeface *ptypefaceB = (FontFaceRec_Typeface*)faceb;
+ SkASSERT(ptypefaceB);
+
+ if (_tcscmp(ptypefaceA->GetFontName(), ptypefaceB->GetFontName())) return false;
+ if (ptypefaceA->GetFontStyle() != ptypefaceB->GetFontStyle()) return false;
+ if (ptypefaceA->GetFontSize() != ptypefaceB->GetFontSize()) return false;
+
+ return true;
+}
+
+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)
+}
+
+#endif // WIN32
+
diff --git a/libsgl/ports/SkGlobals_global.cpp b/libsgl/ports/SkGlobals_global.cpp
new file mode 100644
index 0000000..d87568b
--- /dev/null
+++ b/libsgl/ports/SkGlobals_global.cpp
@@ -0,0 +1,28 @@
+/* libs/graphics/ports/SkGlobals_global.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 "SkGlobals.h"
+#include "SkThread.h"
+
+static SkGlobals::BootStrap gBootStrap;
+
+SkGlobals::BootStrap& SkGlobals::GetBootStrap()
+{
+ return gBootStrap;
+}
+
+
diff --git a/libsgl/ports/SkImageDecoder_Factory.cpp b/libsgl/ports/SkImageDecoder_Factory.cpp
new file mode 100644
index 0000000..791c344
--- /dev/null
+++ b/libsgl/ports/SkImageDecoder_Factory.cpp
@@ -0,0 +1,124 @@
+/* libs/graphics/ports/SkImageDecoder_Factory.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 "SkImageDecoder.h"
+#include "SkMovie.h"
+#include "SkStream.h"
+
+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*);
+extern SkImageDecoder* SkImageDecoder_JPEG_Factory(SkStream*);
+
+typedef SkImageDecoder* (*SkImageDecoderFactoryProc)(SkStream*);
+
+struct CodecFormat {
+ SkImageDecoderFactoryProc fProc;
+ SkImageDecoder::Format fFormat;
+};
+
+static const CodecFormat gPairs[] = {
+ { SkImageDecoder_GIF_Factory, SkImageDecoder::kGIF_Format },
+ { SkImageDecoder_PNG_Factory, SkImageDecoder::kPNG_Format },
+ { 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
+ { SkImageDecoder_JPEG_Factory, SkImageDecoder::kJPEG_Format }
+};
+
+SkImageDecoder* SkImageDecoder::Factory(SkStream* stream) {
+ for (size_t i = 0; i < SK_ARRAY_COUNT(gPairs); i++) {
+ SkImageDecoder* codec = gPairs[i].fProc(stream);
+ stream->rewind();
+ if (NULL != codec) {
+ return codec;
+ }
+ }
+ return NULL;
+}
+
+bool SkImageDecoder::SupportsFormat(Format format) {
+ for (size_t i = 0; i < SK_ARRAY_COUNT(gPairs); i++) {
+ if (gPairs[i].fFormat == format) {
+ return true;
+ }
+ }
+ return false;
+}
+
+/////////////////////////////////////////////////////////////////////////
+
+// the movie may hold onto the stream (by calling ref())
+typedef SkMovie* (*SkMovieStreamProc)(SkStream*);
+// the movie may NOT hold onto the pointer
+typedef SkMovie* (*SkMovieMemoryProc)(const void*, size_t);
+
+extern SkMovie* SkMovie_GIF_StreamFactory(SkStream*);
+extern SkMovie* SkMovie_GIF_MemoryFactory(const void*, size_t);
+
+static const SkMovieStreamProc gStreamProc[] = {
+ SkMovie_GIF_StreamFactory
+};
+
+static const SkMovieMemoryProc gMemoryProc[] = {
+ SkMovie_GIF_MemoryFactory
+};
+
+SkMovie* SkMovie::DecodeStream(SkStream* stream) {
+ for (unsigned i = 0; i < SK_ARRAY_COUNT(gStreamProc); i++) {
+ SkMovie* movie = gStreamProc[i](stream);
+ if (NULL != movie) {
+ return movie;
+ }
+ stream->rewind();
+ }
+ return NULL;
+}
+
+SkMovie* SkMovie::DecodeMemory(const void* data, size_t length)
+{
+ for (unsigned i = 0; i < SK_ARRAY_COUNT(gMemoryProc); i++) {
+ SkMovie* movie = gMemoryProc[i](data, length);
+ if (NULL != movie) {
+ return movie;
+ }
+ }
+ return NULL;
+}
+
+/////////////////////////////////////////////////////////////////////////
+
+#ifdef SK_SUPPORT_IMAGE_ENCODE
+
+extern SkImageEncoder* SkImageEncoder_JPEG_Factory();
+extern SkImageEncoder* SkImageEncoder_PNG_Factory();
+
+SkImageEncoder* SkImageEncoder::Create(Type t) {
+ switch (t) {
+ case kJPEG_Type:
+ return SkImageEncoder_JPEG_Factory();
+ case kPNG_Type:
+ return SkImageEncoder_PNG_Factory();
+ default:
+ return NULL;
+ }
+}
+
+#endif
diff --git a/libsgl/ports/SkImageRef_ashmem.cpp b/libsgl/ports/SkImageRef_ashmem.cpp
new file mode 100644
index 0000000..ef5fc58
--- /dev/null
+++ b/libsgl/ports/SkImageRef_ashmem.cpp
@@ -0,0 +1,195 @@
+#include "SkImageRef_ashmem.h"
+#include "SkImageDecoder.h"
+#include "SkThread.h"
+
+#include <sys/mman.h>
+#include <unistd.h>
+#include <cutils/ashmem.h>
+
+//#define TRACE_ASH_PURGE // just trace purges
+
+#ifdef DUMP_IMAGEREF_LIFECYCLE
+ #define DUMP_ASHMEM_LIFECYCLE
+#else
+// #define DUMP_ASHMEM_LIFECYCLE
+#endif
+
+// ashmem likes lengths on page boundaries
+static size_t roundToPageSize(size_t size) {
+ const size_t mask = getpagesize() - 1;
+ size_t newsize = (size + mask) & ~mask;
+// SkDebugf("---- oldsize %d newsize %d\n", size, newsize);
+ return newsize;
+}
+
+SkImageRef_ashmem::SkImageRef_ashmem(SkStream* stream,
+ SkBitmap::Config config,
+ int sampleSize)
+ : SkImageRef(stream, config, sampleSize) {
+
+ fRec.fFD = -1;
+ fRec.fAddr = NULL;
+ fRec.fSize = 0;
+ fRec.fPinned = false;
+
+ fCT = NULL;
+}
+
+SkImageRef_ashmem::~SkImageRef_ashmem() {
+ fCT->safeUnref();
+
+ if (-1 != fRec.fFD) {
+#ifdef DUMP_ASHMEM_LIFECYCLE
+ SkDebugf("=== ashmem close %d\n", fRec.fFD);
+#endif
+ SkASSERT(fRec.fAddr);
+ SkASSERT(fRec.fSize);
+ munmap(fRec.fAddr, fRec.fSize);
+ close(fRec.fFD);
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+class AshmemAllocator : public SkBitmap::Allocator {
+public:
+ AshmemAllocator(SkAshmemRec* rec, const char name[])
+ : fRec(rec), fName(name) {}
+
+ virtual bool allocPixelRef(SkBitmap* bm, SkColorTable* ct) {
+ const size_t size = roundToPageSize(bm->getSize());
+ int fd = fRec->fFD;
+ void* addr = fRec->fAddr;
+
+ SkASSERT(!fRec->fPinned);
+
+ if (-1 == fd) {
+ SkASSERT(NULL == addr);
+ SkASSERT(0 == fRec->fSize);
+
+ fd = ashmem_create_region(fName, size);
+#ifdef DUMP_ASHMEM_LIFECYCLE
+ SkDebugf("=== ashmem_create_region %s size=%d fd=%d\n", fName, size, fd);
+#endif
+ if (-1 == fd) {
+ SkDebugf("------- imageref_ashmem create failed <%s> %d\n",
+ fName, size);
+ return false;
+ }
+
+ int err = ashmem_set_prot_region(fd, PROT_READ | PROT_WRITE);
+ if (err) {
+ SkDebugf("------ ashmem_set_prot_region(%d) failed %d %d\n",
+ fd, err, errno);
+ return false;
+ }
+
+ addr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
+ if (-1 == (long)addr) {
+ SkDebugf("---------- mmap failed for imageref_ashmem size=%d err=%d\n",
+ size, errno);
+ return false;
+ }
+
+ fRec->fFD = fd;
+ fRec->fAddr = addr;
+ fRec->fSize = size;
+ } else {
+ SkASSERT(addr);
+ SkASSERT(size == fRec->fSize);
+ (void)ashmem_pin_region(fd, 0, 0);
+ }
+
+ bm->setPixels(addr, ct);
+ fRec->fPinned = true;
+ return true;
+ }
+
+private:
+ // we just point to our caller's memory, these are not copies
+ SkAshmemRec* fRec;
+ const char* fName;
+};
+
+bool SkImageRef_ashmem::onDecode(SkImageDecoder* codec, SkStream* stream,
+ SkBitmap* bitmap, SkBitmap::Config config,
+ SkImageDecoder::Mode mode) {
+
+ if (SkImageDecoder::kDecodeBounds_Mode == mode) {
+ return this->INHERITED::onDecode(codec, stream, bitmap, config, mode);
+ }
+
+ AshmemAllocator alloc(&fRec, this->getName());
+
+ codec->setAllocator(&alloc);
+ bool success = this->INHERITED::onDecode(codec, stream, bitmap, config,
+ mode);
+ // remove the allocator, since its on the stack
+ codec->setAllocator(NULL);
+
+ if (success) {
+ // remember the colortable (if any)
+ SkRefCnt_SafeAssign(fCT, bitmap->getColorTable());
+ return true;
+ } else {
+ if (fRec.fPinned) {
+ ashmem_unpin_region(fRec.fFD, 0, 0);
+ fRec.fPinned = false;
+ }
+ return false;
+ }
+}
+
+void* SkImageRef_ashmem::onLockPixels(SkColorTable** ct) {
+ SkASSERT(fBitmap.getPixels() == NULL);
+ SkASSERT(fBitmap.getColorTable() == NULL);
+
+ // fast case: check if we can just pin and get the cached data
+ if (-1 != fRec.fFD) {
+ SkASSERT(fRec.fAddr);
+ SkASSERT(!fRec.fPinned);
+ int pin = ashmem_pin_region(fRec.fFD, 0, 0);
+
+ if (ASHMEM_NOT_PURGED == pin) { // yea, fast case!
+ fBitmap.setPixels(fRec.fAddr, fCT);
+ fRec.fPinned = true;
+ } else if (ASHMEM_WAS_PURGED == pin) {
+ ashmem_unpin_region(fRec.fFD, 0, 0);
+ // let go of our colortable if we lost the pixels. Well get it back
+ // again when we re-decode
+ if (fCT) {
+ fCT->unref();
+ fCT = NULL;
+ }
+#if defined(DUMP_ASHMEM_LIFECYCLE) || defined(TRACE_ASH_PURGE)
+ SkDebugf("===== ashmem purged %d\n", fBitmap.getSize());
+#endif
+ } else {
+ SkDebugf("===== ashmem pin_region(%d) returned %d, treating as error %d\n",
+ fRec.fFD, pin, errno);
+ // return null result for failure
+ if (ct) {
+ *ct = NULL;
+ }
+ return NULL;
+ }
+ } else {
+ // no FD, will create an ashmem region in allocator
+ }
+
+ return this->INHERITED::onLockPixels(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;
+
+ fBitmap.setPixels(NULL, NULL);
+}
+
diff --git a/libsgl/ports/SkImageRef_ashmem.h b/libsgl/ports/SkImageRef_ashmem.h
new file mode 100644
index 0000000..909baea
--- /dev/null
+++ b/libsgl/ports/SkImageRef_ashmem.h
@@ -0,0 +1,33 @@
+#ifndef SkImageRef_ashmem_DEFINED
+#define SkImageRef_ashmem_DEFINED
+
+#include "SkImageRef.h"
+
+struct SkAshmemRec {
+ int fFD;
+ void* fAddr;
+ size_t fSize;
+ bool fPinned;
+};
+
+class SkImageRef_ashmem : public SkImageRef {
+public:
+ SkImageRef_ashmem(SkStream*, SkBitmap::Config, int sampleSize = 1);
+ virtual ~SkImageRef_ashmem();
+
+protected:
+ virtual bool onDecode(SkImageDecoder* codec, SkStream* stream,
+ SkBitmap* bitmap, SkBitmap::Config config,
+ SkImageDecoder::Mode mode);
+
+ virtual void* onLockPixels(SkColorTable**);
+ virtual void onUnlockPixels();
+
+private:
+ SkColorTable* fCT;
+ SkAshmemRec fRec;
+
+ typedef SkImageRef INHERITED;
+};
+
+#endif
diff --git a/libsgl/ports/SkOSEvent_android.cpp b/libsgl/ports/SkOSEvent_android.cpp
new file mode 100644
index 0000000..59d6191
--- /dev/null
+++ b/libsgl/ports/SkOSEvent_android.cpp
@@ -0,0 +1,155 @@
+/* libs/graphics/ports/SkOSEvent_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 "SkEvent.h"
+#include "utils/threads.h"
+#include <stdio.h>
+
+using namespace android;
+
+Mutex gEventQMutex;
+Condition gEventQCondition;
+
+void SkEvent::SignalNonEmptyQueue()
+{
+ gEventQCondition.broadcast();
+}
+
+///////////////////////////////////////////////////////////////////
+
+#ifdef FMS_ARCH_ANDROID_ARM
+
+// don't have pthreads.h, and therefore no timedwait(), so we punt for the demo
+
+void SkEvent::SignalQueueTimer(SkMSec delay)
+{
+}
+
+void SkEvent_start_timer_thread()
+{
+}
+
+void SkEvent_stop_timer_thread()
+{
+}
+
+#else
+
+#include <pthread.h>
+#include <errno.h>
+
+static pthread_t gTimerThread;
+static pthread_mutex_t gTimerMutex;
+static pthread_cond_t gTimerCond;
+static timespec gTimeSpec;
+
+static void* timer_event_thread_proc(void*)
+{
+ for (;;)
+ {
+ int status;
+
+ pthread_mutex_lock(&gTimerMutex);
+
+ timespec spec = gTimeSpec;
+ // mark our global to be zero
+ // so we don't call timedwait again on a stale value
+ gTimeSpec.tv_sec = 0;
+ gTimeSpec.tv_nsec = 0;
+
+ if (spec.tv_sec == 0 && spec.tv_nsec == 0)
+ status = pthread_cond_wait(&gTimerCond, &gTimerMutex);
+ else
+ status = pthread_cond_timedwait(&gTimerCond, &gTimerMutex, &spec);
+
+ if (status == 0) // someone signaled us with a new time
+ {
+ pthread_mutex_unlock(&gTimerMutex);
+ }
+ else
+ {
+ SkASSERT(status == ETIMEDOUT); // no need to unlock the mutex (its unlocked)
+ // this is the payoff. Signal the event queue to wake up
+ // and also check the delay-queue
+ gEventQCondition.broadcast();
+ }
+ }
+ return 0;
+}
+
+#define kThousand (1000)
+#define kMillion (kThousand * kThousand)
+#define kBillion (kThousand * kThousand * kThousand)
+
+void SkEvent::SignalQueueTimer(SkMSec delay)
+{
+ pthread_mutex_lock(&gTimerMutex);
+
+ if (delay)
+ {
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+
+ // normalize tv
+ if (tv.tv_usec >= kMillion)
+ {
+ tv.tv_sec += tv.tv_usec / kMillion;
+ tv.tv_usec %= kMillion;
+ }
+
+ // add tv + delay, scale each up to land on nanoseconds
+ gTimeSpec.tv_nsec = (tv.tv_usec + (delay % kThousand) * kThousand) * kThousand;
+ gTimeSpec.tv_sec = (tv.tv_sec + (delay / kThousand) * kThousand) * kThousand;
+
+ // check for overflow in nsec
+ if ((unsigned long)gTimeSpec.tv_nsec >= kBillion)
+ {
+ gTimeSpec.tv_nsec -= kBillion;
+ gTimeSpec.tv_sec += 1;
+ SkASSERT((unsigned long)gTimeSpec.tv_nsec < kBillion);
+ }
+
+ // printf("SignalQueueTimer(%d) timespec(%d %d)\n", delay, gTimeSpec.tv_sec, gTimeSpec.tv_nsec);
+ }
+ else // cancel the timer
+ {
+ gTimeSpec.tv_nsec = 0;
+ gTimeSpec.tv_sec = 0;
+ }
+
+ pthread_mutex_unlock(&gTimerMutex);
+ pthread_cond_signal(&gTimerCond);
+}
+
+void SkEvent_start_timer_thread()
+{
+ int status;
+ pthread_attr_t attr;
+
+ status = pthread_attr_init(&attr);
+ SkASSERT(status == 0);
+ status = pthread_create(&gTimerThread, &attr, timer_event_thread_proc, 0);
+ SkASSERT(status == 0);
+}
+
+void SkEvent_stop_timer_thread()
+{
+ int status = pthread_cancel(gTimerThread);
+ SkASSERT(status == 0);
+}
+
+#endif
diff --git a/libsgl/ports/SkOSEvent_dummy.cpp b/libsgl/ports/SkOSEvent_dummy.cpp
new file mode 100644
index 0000000..f061b6e
--- /dev/null
+++ b/libsgl/ports/SkOSEvent_dummy.cpp
@@ -0,0 +1,28 @@
+/* libs/graphics/ports/SkOSEvent_dummy.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 "SkEvent.h"
+
+void SkEvent::SignalNonEmptyQueue()
+{
+
+}
+
+void SkEvent::SignalQueueTimer(SkMSec delay)
+{
+
+}
diff --git a/libsgl/ports/SkOSFile_stdio.cpp b/libsgl/ports/SkOSFile_stdio.cpp
new file mode 100644
index 0000000..7438f7b
--- /dev/null
+++ b/libsgl/ports/SkOSFile_stdio.cpp
@@ -0,0 +1,106 @@
+/* libs/graphics/ports/SkOSFile_stdio.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 "SkOSFile.h"
+
+#ifndef SK_BUILD_FOR_BREW
+
+#include <stdio.h>
+#include <errno.h>
+
+SkFILE* sk_fopen(const char path[], SkFILE_Flags flags)
+{
+ char perm[4];
+ char* p = perm;
+
+ if (flags & kRead_SkFILE_Flag)
+ *p++ = 'r';
+ if (flags & kWrite_SkFILE_Flag)
+ *p++ = 'w';
+ *p++ = 'b';
+ *p = 0;
+
+ SkFILE* f = (SkFILE*)::fopen(path, perm);
+#if 0
+ if (NULL == f)
+ SkDebugf("sk_fopen failed for %s (%s), errno=%s\n", path, perm, strerror(errno));
+#endif
+ return f;
+}
+
+size_t sk_fgetsize(SkFILE* f)
+{
+ SkASSERT(f);
+
+ size_t curr = ::ftell((FILE*)f); // remember where we are
+ ::fseek((FILE*)f, 0, SEEK_END); // go to the end
+ size_t size = ::ftell((FILE*)f); // record the size
+ ::fseek((FILE*)f, (long)curr, SEEK_SET); // go back to our prev loc
+ return size;
+}
+
+bool sk_frewind(SkFILE* f)
+{
+ SkASSERT(f);
+ ::rewind((FILE*)f);
+// ::fseek((FILE*)f, 0, SEEK_SET);
+ return true;
+}
+
+size_t sk_fread(void* buffer, size_t byteCount, SkFILE* f)
+{
+ SkASSERT(f);
+ if (buffer == NULL)
+ {
+ size_t curr = ::ftell((FILE*)f);
+ if ((long)curr == -1) {
+ SkDEBUGF(("sk_fread: ftell(%p) returned -1 feof:%d ferror:%d\n", f, feof((FILE*)f), ferror((FILE*)f)));
+ return 0;
+ }
+ // ::fseek((FILE*)f, (long)(curr + byteCount), SEEK_SET);
+ int err = ::fseek((FILE*)f, (long)byteCount, SEEK_CUR);
+ if (err != 0) {
+ SkDEBUGF(("sk_fread: fseek(%d) tell:%d failed with feof:%d ferror:%d returned:%d\n",
+ byteCount, curr, feof((FILE*)f), ferror((FILE*)f), err));
+ return 0;
+ }
+ return byteCount;
+ }
+ else
+ return ::fread(buffer, 1, byteCount, (FILE*)f);
+}
+
+size_t sk_fwrite(const void* buffer, size_t byteCount, SkFILE* f)
+{
+ SkASSERT(f);
+ return ::fwrite(buffer, 1, byteCount, (FILE*)f);
+}
+
+void sk_fflush(SkFILE* f)
+{
+ SkASSERT(f);
+ ::fflush((FILE*)f);
+}
+
+void sk_fclose(SkFILE* f)
+{
+ SkASSERT(f);
+ ::fclose((FILE*)f);
+}
+
+#endif
+
diff --git a/libsgl/ports/SkThread_none.cpp b/libsgl/ports/SkThread_none.cpp
new file mode 100644
index 0000000..37a3834
--- /dev/null
+++ b/libsgl/ports/SkThread_none.cpp
@@ -0,0 +1,49 @@
+/* libs/graphics/ports/SkThread_none.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 "SkThread.h"
+
+int32_t sk_atomic_inc(int32_t* addr)
+{
+ int32_t value = *addr;
+ *addr = value + 1;
+ return value;
+}
+
+int32_t sk_atomic_dec(int32_t* addr)
+{
+ int32_t value = *addr;
+ *addr = value - 1;
+ return value;
+}
+
+SkMutex::SkMutex(bool /* isGlobal */)
+{
+}
+
+SkMutex::~SkMutex()
+{
+}
+
+void SkMutex::acquire()
+{
+}
+
+void SkMutex::release()
+{
+}
+
diff --git a/libsgl/ports/SkThread_pthread.cpp b/libsgl/ports/SkThread_pthread.cpp
new file mode 100644
index 0000000..4ee857d
--- /dev/null
+++ b/libsgl/ports/SkThread_pthread.cpp
@@ -0,0 +1,90 @@
+#include "SkThread.h"
+
+#include <pthread.h>
+#include <errno.h>
+
+SkMutex gAtomicMutex;
+
+int32_t sk_atomic_inc(int32_t* addr)
+{
+ SkAutoMutexAcquire ac(gAtomicMutex);
+
+ int32_t value = *addr;
+ *addr = value + 1;
+ return value;
+}
+
+int32_t sk_atomic_dec(int32_t* addr)
+{
+ SkAutoMutexAcquire ac(gAtomicMutex);
+
+ int32_t value = *addr;
+ *addr = value - 1;
+ return value;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+static void print_pthread_error(int status)
+{
+ switch (status) {
+ case 0: // success
+ break;
+ case EINVAL:
+ printf("pthread error [%d] EINVAL\n", status);
+ break;
+ case EBUSY:
+ printf("pthread error [%d] EBUSY\n", status);
+ break;
+ default:
+ printf("pthread error [%d] unknown\n", status);
+ break;
+ }
+}
+
+SkMutex::SkMutex(bool isGlobal) : fIsGlobal(isGlobal)
+{
+ if (sizeof(pthread_mutex_t) > sizeof(fStorage))
+ {
+ SkDEBUGF(("pthread mutex size = %d\n", sizeof(pthread_mutex_t)));
+ SkASSERT(!"mutex storage is too small");
+ }
+
+ int status;
+ pthread_mutexattr_t attr;
+
+ status = pthread_mutexattr_init(&attr);
+ print_pthread_error(status);
+ SkASSERT(0 == status);
+
+ status = pthread_mutex_init((pthread_mutex_t*)fStorage, &attr);
+ print_pthread_error(status);
+ SkASSERT(0 == status);
+}
+
+SkMutex::~SkMutex()
+{
+ int status = pthread_mutex_destroy((pthread_mutex_t*)fStorage);
+
+ // only report errors on non-global mutexes
+ if (!fIsGlobal)
+ {
+ print_pthread_error(status);
+ SkASSERT(0 == status);
+ }
+}
+
+void SkMutex::acquire()
+{
+ int status = pthread_mutex_lock((pthread_mutex_t*)fStorage);
+ print_pthread_error(status);
+ SkASSERT(0 == status);
+}
+
+void SkMutex::release()
+{
+ int status = pthread_mutex_unlock((pthread_mutex_t*)fStorage);
+ print_pthread_error(status);
+ SkASSERT(0 == status);
+}
+
diff --git a/libsgl/ports/SkThread_win.cpp b/libsgl/ports/SkThread_win.cpp
new file mode 100644
index 0000000..d3f3e21
--- /dev/null
+++ b/libsgl/ports/SkThread_win.cpp
@@ -0,0 +1,64 @@
+/* libs/graphics/ports/SkThread_none.cpp
+**
+** 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.
+** 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 <windows.h>
+#include "SkThread.h"
+
+namespace {
+
+template <bool>
+struct CompileAssert {
+};
+
+} // namespace
+
+#define COMPILE_ASSERT(expr, msg) \
+ typedef CompileAssert<(bool(expr))> msg[bool(expr) ? 1 : -1]
+
+int32_t sk_atomic_inc(int32_t* addr)
+{
+ // InterlockedIncrement returns the new value, we want to return the old.
+ return InterlockedIncrement(reinterpret_cast<LONG*>(addr)) - 1;
+}
+
+int32_t sk_atomic_dec(int32_t* addr)
+{
+ return InterlockedDecrement(reinterpret_cast<LONG*>(addr)) + 1;
+}
+
+SkMutex::SkMutex(bool /* isGlobal */)
+{
+ COMPILE_ASSERT(sizeof(fStorage) > sizeof(CRITICAL_SECTION),
+ NotEnoughSizeForCriticalSection);
+ InitializeCriticalSection(reinterpret_cast<CRITICAL_SECTION*>(&fStorage));
+}
+
+SkMutex::~SkMutex()
+{
+ DeleteCriticalSection(reinterpret_cast<CRITICAL_SECTION*>(&fStorage));
+}
+
+void SkMutex::acquire()
+{
+ EnterCriticalSection(reinterpret_cast<CRITICAL_SECTION*>(&fStorage));
+}
+
+void SkMutex::release()
+{
+ LeaveCriticalSection(reinterpret_cast<CRITICAL_SECTION*>(&fStorage));
+}
+
diff --git a/libsgl/ports/SkTime_Unix.cpp b/libsgl/ports/SkTime_Unix.cpp
new file mode 100644
index 0000000..1bf3a76
--- /dev/null
+++ b/libsgl/ports/SkTime_Unix.cpp
@@ -0,0 +1,50 @@
+/* libs/graphics/ports/SkTime_Unix.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 "SkTime.h"
+
+#if defined(SK_BUILD_FOR_UNIX) || defined(SK_BUILD_FOR_MAC)
+#include <sys/time.h>
+#include <time.h>
+
+void SkTime::GetDateTime(DateTime* dt)
+{
+ if (dt)
+ {
+ time_t m_time;
+ time(&m_time);
+ struct tm* tstruct;
+ tstruct = localtime(&m_time);
+
+ dt->fYear = tstruct->tm_year;
+ dt->fMonth = SkToU8(tstruct->tm_mon + 1);
+ dt->fDayOfWeek = SkToU8(tstruct->tm_wday);
+ dt->fDay = SkToU8(tstruct->tm_mday);
+ dt->fHour = SkToU8(tstruct->tm_hour);
+ dt->fMinute = SkToU8(tstruct->tm_min);
+ dt->fSecond = SkToU8(tstruct->tm_sec);
+ }
+}
+
+SkMSec SkTime::GetMSecs()
+{
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ return (SkMSec) (tv.tv_sec * 1000 + tv.tv_usec / 1000 ); // microseconds to milliseconds
+}
+
+#endif
diff --git a/libsgl/ports/SkXMLParser_empty.cpp b/libsgl/ports/SkXMLParser_empty.cpp
new file mode 100644
index 0000000..9a27306
--- /dev/null
+++ b/libsgl/ports/SkXMLParser_empty.cpp
@@ -0,0 +1,36 @@
+/* libs/graphics/ports/SkXMLParser_empty.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.
+*/
+
+// Copyright Skia Inc. 2004 - 2005
+//
+#include "SkXMLParser.h"
+
+bool SkXMLParser::parse(SkStream& docStream)
+{
+ return false;
+}
+
+bool SkXMLParser::parse(const char doc[], size_t len)
+{
+ return false;
+}
+
+void SkXMLParser::GetNativeErrorString(int error, SkString* str)
+{
+
+}
+
diff --git a/libsgl/ports/SkXMLParser_expat.cpp b/libsgl/ports/SkXMLParser_expat.cpp
new file mode 100644
index 0000000..7694d50
--- /dev/null
+++ b/libsgl/ports/SkXMLParser_expat.cpp
@@ -0,0 +1,149 @@
+/* libs/graphics/ports/SkXMLParser_expat.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 "SkXMLParser.h"
+#include "SkString.h"
+#include "SkStream.h"
+
+#include "expat.h"
+
+#ifdef SK_BUILD_FOR_PPI
+#define CHAR_16_TO_9
+#endif
+
+#if defined CHAR_16_TO_9
+inline size_t sk_wcslen(const short* char16) {
+ const short* start = char16;
+ while (*char16)
+ char16++;
+ return char16 - start;
+}
+
+inline const char* ConvertUnicodeToChar(const short* ch16, size_t len, SkAutoMalloc& ch8Malloc) {
+ char* ch8 = (char*) ch8Malloc.get();
+ int index;
+ for (index = 0; index < len; index++)
+ ch8[index] = (char) ch16[index];
+ ch8[index] = '\0';
+ return ch8;
+}
+#endif
+
+static void XMLCALL start_proc(void *data, const char *el, const char **attr)
+{
+#if defined CHAR_16_TO_9
+ size_t len = sk_wcslen((const short*) el);
+ SkAutoMalloc el8(len + 1);
+ el = ConvertUnicodeToChar((const short*) el, len, el8);
+#endif
+ if (((SkXMLParser*)data)->startElement(el)) {
+ XML_StopParser((XML_Parser) ((SkXMLParser*)data)->fParser, false);
+ return;
+ }
+ while (*attr)
+ {
+ const char* attr0 = attr[0];
+ const char* attr1 = attr[1];
+#if defined CHAR_16_TO_9
+ size_t len0 = sk_wcslen((const short*) attr0);
+ SkAutoMalloc attr0_8(len0 + 1);
+ attr0 = ConvertUnicodeToChar((const short*) attr0, len0, attr0_8);
+ size_t len1 = sk_wcslen((const short*) attr1);
+ SkAutoMalloc attr1_8(len1 + 1);
+ attr1 = ConvertUnicodeToChar((const short*) attr1, len1, attr1_8);
+#endif
+ if (((SkXMLParser*)data)->addAttribute(attr0, attr1)) {
+ XML_StopParser((XML_Parser) ((SkXMLParser*)data)->fParser, false);
+ return;
+ }
+ attr += 2;
+ }
+}
+
+static void XMLCALL end_proc(void *data, const char *el)
+{
+#if defined CHAR_16_TO_9
+ size_t len = sk_wcslen((const short*) el);
+ SkAutoMalloc el8(len + 1);
+ el = ConvertUnicodeToChar((const short*) el, len, el8);
+#endif
+ if (((SkXMLParser*)data)->endElement(el))
+ XML_StopParser((XML_Parser) ((SkXMLParser*)data)->fParser, false);
+}
+
+static void XMLCALL text_proc(void* data, const char* text, int len)
+{
+#if defined CHAR_16_TO_9
+ SkAutoMalloc text8(len + 1);
+ text = ConvertUnicodeToChar((const short*) text, len, text8);
+#endif
+ if (((SkXMLParser*)data)->text(text, len))
+ XML_StopParser((XML_Parser) ((SkXMLParser*)data)->fParser, false);
+}
+
+bool SkXMLParser::parse(const char doc[], size_t len)
+{
+ if (len == 0) {
+ fError->fCode = SkXMLParserError::kEmptyFile;
+ reportError(NULL);
+ return false;
+ }
+ XML_Parser p = XML_ParserCreate(NULL);
+ SkASSERT(p);
+ fParser = p;
+ XML_SetElementHandler(p, start_proc, end_proc);
+ XML_SetCharacterDataHandler(p, text_proc);
+ XML_SetUserData(p, this);
+
+ bool success = true;
+ int error = XML_Parse(p, doc, len, true);
+ if (error == XML_STATUS_ERROR) {
+ reportError(p);
+ success = false;
+ }
+ XML_ParserFree(p);
+ return success;
+}
+
+bool SkXMLParser::parse(SkStream& input)
+{
+ size_t len = input.read(NULL, 0);
+ SkAutoMalloc am(len);
+ char* doc = (char*)am.get();
+
+ input.rewind();
+ size_t len2 = input.read(doc, len);
+ SkASSERT(len2 == len);
+
+ return this->parse(doc, len2);
+}
+
+void SkXMLParser::reportError(void* p)
+{
+ XML_Parser parser = (XML_Parser) p;
+ if (fError && parser) {
+ fError->fNativeCode = XML_GetErrorCode(parser);
+ fError->fLineNumber = XML_GetCurrentLineNumber(parser);
+ }
+}
+
+void SkXMLParser::GetNativeErrorString(int error, SkString* str)
+{
+ if (str)
+ str->set(XML_ErrorString((XML_Error) error));
+}
+
diff --git a/libsgl/ports/SkXMLParser_tinyxml.cpp b/libsgl/ports/SkXMLParser_tinyxml.cpp
new file mode 100644
index 0000000..7f57b80
--- /dev/null
+++ b/libsgl/ports/SkXMLParser_tinyxml.cpp
@@ -0,0 +1,96 @@
+/* libs/graphics/ports/SkXMLParser_tinyxml.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 "SkXMLParser.h"
+#include "SkStream.h"
+#include "SkTemplates.h"
+#include "tinyxml.h"
+
+static void walk_elem(SkXMLParser* parser, const TiXmlElement* elem)
+{
+ //printf("walk_elem(%s) ", elem->Value());
+
+ parser->startElement(elem->Value());
+
+ const TiXmlAttribute* attr = elem->FirstAttribute();
+ while (attr)
+ {
+ //printf("walk_elem_attr(%s=\"%s\") ", attr->Name(), attr->Value());
+
+ parser->addAttribute(attr->Name(), attr->Value());
+ attr = attr->Next();
+ }
+ //printf("\n");
+
+ const TiXmlNode* node = elem->FirstChild();
+ while (node)
+ {
+ if (node->ToElement())
+ walk_elem(parser, node->ToElement());
+ else if (node->ToText())
+ parser->text(node->Value(), strlen(node->Value()));
+ node = node->NextSibling();
+ }
+
+ parser->endElement(elem->Value());
+}
+
+static bool load_buf(SkXMLParser* parser, const char buf[])
+{
+ TiXmlDocument doc;
+
+ (void)doc.Parse(buf);
+ if (doc.Error())
+ {
+ printf("tinyxml error: <%s> row[%d] col[%d]\n", doc.ErrorDesc(), doc.ErrorRow(), doc.ErrorCol());
+ return false;
+ }
+
+ walk_elem(parser, doc.RootElement());
+ return true;
+}
+
+bool SkXMLParser::parse(SkStream& stream)
+{
+ size_t size = stream.read(NULL, 0);
+
+ SkAutoMalloc buffer(size + 1);
+ char* buf = (char*)buffer.get();
+
+ stream.read(buf, size);
+ buf[size] = 0;
+
+ return load_buf(this, buf);
+}
+
+bool SkXMLParser::parse(const char doc[], size_t len)
+{
+ SkAutoMalloc buffer(len + 1);
+ char* buf = (char*)buffer.get();
+
+ memcpy(buf, doc, len);
+ buf[len] = 0;
+
+ return load_buf(this, buf);
+}
+
+void SkXMLParser::GetNativeErrorString(int error, SkString* str)
+{
+ if (str)
+ str->set("GetNativeErrorString not implemented for TinyXml");
+}
+
diff --git a/libsgl/ports/SkXMLPullParser_expat.cpp b/libsgl/ports/SkXMLPullParser_expat.cpp
new file mode 100644
index 0000000..949c7a9
--- /dev/null
+++ b/libsgl/ports/SkXMLPullParser_expat.cpp
@@ -0,0 +1,222 @@
+/* libs/graphics/ports/SkXMLParser_expat.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 "SkXMLParser.h"
+#include "SkChunkAlloc.h"
+#include "SkString.h"
+#include "SkStream.h"
+
+#include "expat.h"
+
+static inline char* dupstr(SkChunkAlloc& chunk, const char src[], size_t len)
+{
+ SkASSERT(src);
+ char* dst = (char*)chunk.alloc(len + 1, SkChunkAlloc::kThrow_AllocFailType);
+
+ memcpy(dst, src, len);
+ dst[len] = 0;
+ return dst;
+}
+
+static inline int count_pairs(const char** p)
+{
+ const char** start = p;
+ while (*p)
+ {
+ SkASSERT(p[1] != NULL);
+ p += 2;
+ }
+ return (p - start) >> 1;
+}
+
+struct Data {
+ Data() : fAlloc(2048), fState(NORMAL) {}
+
+ XML_Parser fParser;
+ SkXMLPullParser::Curr* fCurr;
+ SkChunkAlloc fAlloc;
+
+ enum State {
+ NORMAL,
+ MISSED_START_TAG,
+ RETURN_END_TAG
+ };
+ State fState;
+ const char* fEndTag; // if state is RETURN_END_TAG
+};
+
+static void XMLCALL start_proc(void *data, const char *el, const char **attr)
+{
+ Data* p = (Data*)data;
+ SkXMLPullParser::Curr* c = p->fCurr;
+ SkChunkAlloc& alloc = p->fAlloc;
+
+ c->fName = dupstr(alloc, el, strlen(el));
+
+ int n = count_pairs(attr);
+ SkXMLPullParser::AttrInfo* info = (SkXMLPullParser::AttrInfo*)alloc.alloc(n * sizeof(SkXMLPullParser::AttrInfo),
+ SkChunkAlloc::kThrow_AllocFailType);
+ c->fAttrInfoCount = n;
+ c->fAttrInfos = info;
+
+ for (int i = 0; i < n; i++)
+ {
+ info[i].fName = dupstr(alloc, attr[0], strlen(attr[0]));
+ info[i].fValue = dupstr(alloc, attr[1], strlen(attr[1]));
+ attr += 2;
+ }
+
+ c->fEventType = SkXMLPullParser::START_TAG;
+ XML_StopParser(p->fParser, true);
+}
+
+static void XMLCALL end_proc(void *data, const char *el)
+{
+ Data* p = (Data*)data;
+ SkXMLPullParser::Curr* c = p->fCurr;
+
+ if (c->fEventType == SkXMLPullParser::START_TAG)
+ {
+ /* if we get here, we were called with a start_tag immediately
+ followed by this end_tag. The caller will only see the end_tag,
+ so we set a flag to notify them of the missed start_tag
+ */
+ p->fState = Data::MISSED_START_TAG;
+
+ SkASSERT(c->fName != NULL);
+ SkASSERT(strcmp(c->fName, el) == 0);
+ }
+ else
+ c->fName = dupstr(p->fAlloc, el, strlen(el));
+
+ c->fEventType = SkXMLPullParser::END_TAG;
+ XML_StopParser(p->fParser, true);
+}
+
+#include <ctype.h>
+
+static bool isws(const char s[])
+{
+ for (; *s; s++)
+ if (!isspace(*s))
+ return false;
+ return true;
+}
+
+static void XMLCALL text_proc(void* data, const char* text, int len)
+{
+ Data* p = (Data*)data;
+ SkXMLPullParser::Curr* c = p->fCurr;
+
+ c->fName = dupstr(p->fAlloc, text, len);
+ c->fIsWhitespace = isws(c->fName);
+
+ c->fEventType = SkXMLPullParser::TEXT;
+ XML_StopParser(p->fParser, true);
+}
+
+//////////////////////////////////////////////////////////////////////////
+
+struct SkXMLPullParser::Impl {
+ Data fData;
+ void* fBuffer;
+ size_t fBufferLen;
+};
+
+static void reportError(XML_Parser parser)
+{
+ XML_Error code = XML_GetErrorCode(parser);
+ int lineNumber = XML_GetCurrentLineNumber(parser);
+ const char* msg = XML_ErrorString(code);
+
+ printf("-------- XML error [%d] on line %d, %s\n", code, lineNumber, msg);
+}
+
+bool SkXMLPullParser::onInit()
+{
+ fImpl = new Impl;
+
+ XML_Parser p = XML_ParserCreate(NULL);
+ SkASSERT(p);
+
+ fImpl->fData.fParser = p;
+ fImpl->fData.fCurr = &fCurr;
+
+ XML_SetElementHandler(p, start_proc, end_proc);
+ XML_SetCharacterDataHandler(p, text_proc);
+ XML_SetUserData(p, &fImpl->fData);
+
+ size_t len = fStream->read(NULL, 0);
+ fImpl->fBufferLen = len;
+ fImpl->fBuffer = sk_malloc_throw(len);
+ fStream->rewind();
+ size_t len2 = fStream->read(fImpl->fBuffer, len);
+ return len2 == len;
+}
+
+void SkXMLPullParser::onExit()
+{
+ sk_free(fImpl->fBuffer);
+ XML_ParserFree(fImpl->fData.fParser);
+ delete fImpl;
+ fImpl = NULL;
+}
+
+SkXMLPullParser::EventType SkXMLPullParser::onNextToken()
+{
+ if (Data::RETURN_END_TAG == fImpl->fData.fState)
+ {
+ fImpl->fData.fState = Data::NORMAL;
+ fCurr.fName = fImpl->fData.fEndTag; // restore name from (below) save
+ return SkXMLPullParser::END_TAG;
+ }
+
+ fImpl->fData.fAlloc.reuse();
+
+ XML_Parser p = fImpl->fData.fParser;
+ XML_Status status;
+
+ status = XML_ResumeParser(p);
+
+CHECK_STATUS:
+ switch (status) {
+ case XML_STATUS_OK:
+ return SkXMLPullParser::END_DOCUMENT;
+
+ case XML_STATUS_ERROR:
+ if (XML_GetErrorCode(p) != XML_ERROR_NOT_SUSPENDED)
+ {
+ reportError(p);
+ return SkXMLPullParser::ERROR;
+ }
+ status = XML_Parse(p, (const char*)fImpl->fBuffer, fImpl->fBufferLen, true);
+ goto CHECK_STATUS;
+
+ case XML_STATUS_SUSPENDED:
+ if (Data::MISSED_START_TAG == fImpl->fData.fState)
+ {
+ // return a start_tag, and clear the flag so we return end_tag next
+ SkASSERT(SkXMLPullParser::END_TAG == fCurr.fEventType);
+ fImpl->fData.fState = Data::RETURN_END_TAG;
+ fImpl->fData.fEndTag = fCurr.fName; // save this pointer
+ return SkXMLPullParser::START_TAG;
+ }
+ break;
+ }
+ return fCurr.fEventType;
+}
+
diff --git a/libsgl/ports/sk_predefined_gamma.h b/libsgl/ports/sk_predefined_gamma.h
new file mode 100644
index 0000000..0818b30
--- /dev/null
+++ b/libsgl/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