| yangsu@google.com | 1a2b4c1 | 2011-06-24 17:20:50 +0000 | [diff] [blame] | 1 | #import <UIKit/UIKit.h> | 
 | 2 |  | 
 | 3 | #include "SkStream_NSData.h" | 
 | 4 | #include "SkTypeface.h" | 
 | 5 | #include "SkFontHost.h" | 
 | 6 | #include "SkThread.h" | 
 | 7 | #include "SkTemplates.h" | 
 | 8 |  | 
 | 9 | enum FontDesign { | 
 | 10 |     kUnknown_Design, | 
 | 11 |     kSans_FontDesign, | 
 | 12 |     kSerif_FontDesign, | 
 | 13 |  | 
 | 14 |     kIllegal_FontDesign,    // never use with a real font | 
 | 15 | }; | 
 | 16 |  | 
 | 17 | // returns kIllegal_FontDesign if not found | 
 | 18 | static FontDesign find_design_from_name(const char name[]) { | 
 | 19 |     static const struct { | 
 | 20 |         const char* fName; | 
 | 21 |         FontDesign  fDesign; | 
 | 22 |     } gRec[] = { | 
 | 23 |         { "sans-serif", kSans_FontDesign }, | 
 | 24 |         { "serif",      kSerif_FontDesign }, | 
 | 25 |     }; | 
 | 26 |  | 
 | 27 |     for (size_t i = 0; i < SK_ARRAY_COUNT(gRec); i++) { | 
 | 28 |         if (!strcasecmp(name, gRec[i].fName)) { | 
 | 29 |             return gRec[i].fDesign; | 
 | 30 |         } | 
 | 31 |     } | 
 | 32 |     return kIllegal_FontDesign; | 
 | 33 | } | 
 | 34 |  | 
 | 35 | struct FontRes { | 
 | 36 |     const char*         fName; | 
 | 37 |     SkTypeface::Style   fStyle; | 
 | 38 |     FontDesign          fDesign; | 
 | 39 | }; | 
 | 40 |  | 
 | 41 | static const FontRes gFontRes[] = { | 
 | 42 |     { "DroidSans",          SkTypeface::kNormal,    kSans_FontDesign    }, | 
 | 43 |     { "DroidSans",          SkTypeface::kBold,      kSans_FontDesign    }, | 
 | 44 |     { "DroidSerif-Regular", SkTypeface::kNormal,    kSerif_FontDesign    }, | 
 | 45 |     { "DroidSerif-Bold",    SkTypeface::kBold,      kSerif_FontDesign    }, | 
 | 46 | //    { "PescaderoPro",       SkTypeface::kNormal,    kSerif_FontDesign   }, | 
 | 47 | //    { "PescaderoPro-Bold",  SkTypeface::kBold,      kSerif_FontDesign   }, | 
 | 48 | }; | 
 | 49 | #define FONTRES_COUNT SK_ARRAY_COUNT(gFontRes) | 
 | 50 |  | 
 | 51 | #define DEFAULT_INDEX_REGULAR   1 | 
 | 52 | #define DEFAULT_INDEX_BOLD      2 | 
 | 53 |  | 
 | 54 | /////////////////////////////////////////////////////////////////////////////// | 
 | 55 |  | 
 | 56 | class SkTypeface_Stream : public SkTypeface { | 
 | 57 | public: | 
 | 58 |     SkTypeface_Stream(SkStream* stream, Style style); | 
 | 59 |     virtual ~SkTypeface_Stream(); | 
 | 60 |  | 
 | 61 |     SkStream* refStream() { | 
 | 62 |         fStream->ref(); | 
 | 63 |         return fStream; | 
 | 64 |     } | 
 | 65 |  | 
 | 66 | private: | 
 | 67 |     SkStream*   fStream; | 
 | 68 | }; | 
 | 69 |  | 
 | 70 | static int32_t gUniqueFontID; | 
 | 71 |  | 
 | 72 | SkTypeface_Stream::SkTypeface_Stream(SkStream* stream, Style style) | 
 | 73 | : SkTypeface(style, sk_atomic_inc(&gUniqueFontID) + 1) { | 
 | 74 |     fStream = stream; | 
 | 75 |     fStream->ref(); | 
 | 76 | } | 
 | 77 |  | 
 | 78 | SkTypeface_Stream::~SkTypeface_Stream() { | 
 | 79 |     fStream->unref(); | 
 | 80 | } | 
 | 81 |  | 
 | 82 | static SkTypeface_Stream* create_from_fontres(const FontRes& res) { | 
 | 83 |     SkStream* stream = SkStream_NSData::CreateFromResource(res.fName, "ttf"); | 
 | 84 |     SkAutoUnref aur(stream); | 
 | 85 |  | 
 | 86 |     return SkNEW_ARGS(SkTypeface_Stream, (stream, res.fStyle)); | 
 | 87 | } | 
 | 88 |  | 
 | 89 | /////////////////////////////////////////////////////////////////////////////// | 
 | 90 |  | 
 | 91 | static int compute_style_distance(SkTypeface::Style a, SkTypeface::Style b) { | 
 | 92 |     int dist = 0; | 
 | 93 |     int diff = a ^ b; | 
 | 94 |     if (diff & SkTypeface::kBold) { | 
 | 95 |         dist += 2; | 
 | 96 |     } | 
 | 97 |     if (diff & SkTypeface::kItalic) { | 
 | 98 |         dist += 1; | 
 | 99 |     } | 
 | 100 |     return dist; | 
 | 101 | } | 
 | 102 |  | 
 | 103 | static SkTypeface_Stream* gFonts[FONTRES_COUNT]; | 
 | 104 |  | 
 | 105 | static void assure_init_fonts() { | 
 | 106 |     static bool gOnce; | 
 | 107 |     if (!gOnce) { | 
 | 108 |         for (size_t i = 0; i < FONTRES_COUNT; i++) { | 
 | 109 |             gFonts[i] = create_from_fontres(gFontRes[i]); | 
 | 110 |             gOnce = true; | 
 | 111 |         } | 
 | 112 |     } | 
 | 113 | } | 
 | 114 |  | 
 | 115 | static SkTypeface_Stream* get_default_font(SkTypeface::Style style) { | 
 | 116 |     assure_init_fonts(); | 
 | 117 |  | 
 | 118 |     if (style & SkTypeface::kBold) { | 
 | 119 |         return gFonts[DEFAULT_INDEX_BOLD]; | 
 | 120 |     } else { | 
 | 121 |         return gFonts[DEFAULT_INDEX_REGULAR]; | 
 | 122 |     } | 
 | 123 | } | 
 | 124 |  | 
 | 125 | static SkTypeface_Stream* find_by_id(SkFontID fontID) { | 
 | 126 |     assure_init_fonts(); | 
 | 127 |      | 
 | 128 |     for (size_t i = 0; i < FONTRES_COUNT; i++) { | 
 | 129 |         if (gFonts[i]->uniqueID() == fontID) { | 
 | 130 |             return gFonts[i]; | 
 | 131 |         } | 
 | 132 |     } | 
 | 133 |     return NULL; | 
 | 134 | } | 
 | 135 |  | 
 | 136 | /////////////////////////////////////////////////////////////////////////////// | 
 | 137 |  | 
 | 138 | template <typename T> T* ref_and_return(T* obj) { | 
 | 139 |     obj->ref(); | 
 | 140 |     return obj; | 
 | 141 | } | 
 | 142 |  | 
 | 143 | SkTypeface* SkFontHost::CreateTypeface(const SkTypeface* familyFace, | 
 | 144 |                                      const char familyName[], | 
 | 145 |                                      const void* data, size_t bytelength, | 
 | 146 |                                      SkTypeface::Style style) { | 
 | 147 |     assure_init_fonts(); | 
 | 148 |  | 
 | 149 |     if (familyName) { | 
 | 150 |         FontDesign design = find_design_from_name(familyName); | 
 | 151 |         if (kIllegal_FontDesign != design) { | 
 | 152 |             familyName = "$#@*&%*#$@ never match any name"; | 
 | 153 |         } | 
 | 154 |  | 
 | 155 |         int bestDistance = 999; | 
 | 156 |         int bestIndex = -1; | 
 | 157 |         for (size_t i = 0; i < FONTRES_COUNT; i++) { | 
 | 158 |             if (design == gFontRes[i].fDesign || !strcmp(gFontRes[i].fName, familyName)) { | 
 | 159 |                 int dist = compute_style_distance(style, gFontRes[i].fStyle); | 
 | 160 |                 if (dist < bestDistance) { | 
 | 161 |                     bestDistance = dist; | 
 | 162 |                     bestIndex = i; | 
 | 163 |                 } | 
 | 164 |             } | 
 | 165 |         } | 
 | 166 |         if (bestIndex >= 0) { | 
 | 167 |             return ref_and_return(gFonts[bestIndex]); | 
 | 168 |         } | 
 | 169 |     } | 
 | 170 |  | 
 | 171 |     return ref_and_return(get_default_font(style)); | 
 | 172 | } | 
 | 173 |  | 
 | 174 | SkTypeface* SkFontHost::CreateTypefaceFromStream(SkStream* stream) { | 
| mtklein@google.com | 330313a | 2013-08-22 15:37:26 +0000 | [diff] [blame] | 175 |     SkDEBUGFAIL("SkFontHost::CreateTypeface unimplemented"); | 
| yangsu@google.com | 1a2b4c1 | 2011-06-24 17:20:50 +0000 | [diff] [blame] | 176 |     return NULL; | 
 | 177 | } | 
 | 178 |  | 
 | 179 | SkTypeface* SkFontHost::CreateTypefaceFromFile(char const*) { | 
| mtklein@google.com | 330313a | 2013-08-22 15:37:26 +0000 | [diff] [blame] | 180 | //    SkDEBUGFAIL("SkFontHost::CreateTypefaceFromFile unimplemented"); | 
| yangsu@google.com | 1a2b4c1 | 2011-06-24 17:20:50 +0000 | [diff] [blame] | 181 |     return NULL; | 
 | 182 | } | 
 | 183 |  | 
 | 184 | /////////////////////////////////////////////////////////////////////////////// | 
 | 185 |  | 
| yangsu@google.com | 1a2b4c1 | 2011-06-24 17:20:50 +0000 | [diff] [blame] | 186 | SkStream* SkFontHost::OpenStream(uint32_t uniqueID) { | 
 | 187 |     SkTypeface_Stream* tf = find_by_id(uniqueID); | 
 | 188 |     SkASSERT(tf); | 
 | 189 |     return tf->refStream(); | 
 | 190 | } | 
 | 191 |  | 
 | 192 | size_t SkFontHost::GetFileName(SkFontID fontID, char path[], size_t length, | 
 | 193 |                                int32_t* index) { | 
 | 194 |     SkDebugf("SkFontHost::GetFileName unimplemented\n"); | 
 | 195 |     return 0; | 
 | 196 | } | 
 | 197 |  | 
 | 198 | /////////////////////////////////////////////////////////////////////////////// | 
 | 199 |  | 
 | 200 | void SkFontHost::Serialize(const SkTypeface* face, SkWStream* stream) { | 
| mtklein@google.com | 330313a | 2013-08-22 15:37:26 +0000 | [diff] [blame] | 201 |     SkDEBUGFAIL("SkFontHost::Serialize unimplemented"); | 
| yangsu@google.com | 1a2b4c1 | 2011-06-24 17:20:50 +0000 | [diff] [blame] | 202 | } | 
 | 203 |  | 
 | 204 | SkTypeface* SkFontHost::Deserialize(SkStream* stream) { | 
 | 205 |     int style = stream->readU8(); | 
 | 206 |     int len = stream->readPackedUInt(); | 
 | 207 |     const char* name = NULL; | 
 | 208 |     if (len > 0) { | 
 | 209 |         SkString str; | 
 | 210 |         str.resize(len); | 
 | 211 |         stream->read(str.writable_str(), len); | 
 | 212 |          | 
 | 213 |         if (str.startsWith("DroidSans")) { | 
 | 214 |             name = "sans-serif"; | 
 | 215 |         } else if (str.startsWith("DroidSerif")) { | 
 | 216 |             name = "serif"; | 
 | 217 |         } | 
 | 218 |         SkDebugf("---- deserialize typeface <%s> %d %s\n", str.c_str(), style, name); | 
 | 219 |     } | 
 | 220 | //    name = NULL; style = 0; | 
 | 221 |     return SkFontHost::CreateTypeface(NULL, name, NULL, NULL, | 
 | 222 |                                       (SkTypeface::Style)style); | 
 | 223 | } | 
 | 224 |  | 
 | 225 | SkFontID SkFontHost::NextLogicalFont(SkFontID currFontID, SkFontID origFontID) { | 
 | 226 |     return 0; | 
 | 227 | } | 
 | 228 |  | 
 | 229 | #define FONT_CACHE_MEMORY_BUDGET    1 * 1024 * 1024 | 
 | 230 |  | 
 | 231 | size_t SkFontHost::ShouldPurgeFontCache(size_t sizeAllocatedSoFar) { | 
 | 232 |     if (sizeAllocatedSoFar > FONT_CACHE_MEMORY_BUDGET) | 
 | 233 |         return sizeAllocatedSoFar - FONT_CACHE_MEMORY_BUDGET; | 
 | 234 |     else | 
 | 235 |         return 0;   // nothing to do | 
 | 236 | } | 
 | 237 |  | 
 | 238 | /////////////////////////////////////////////////////////////////////////////// | 
 | 239 | int SkFontHost::ComputeGammaFlag(const SkPaint& paint) { | 
 | 240 |     return 0; | 
 | 241 | } | 
 | 242 |  | 
 | 243 | void SkFontHost::GetGammaTables(const uint8_t* tables[2]) { | 
 | 244 |     tables[0] = NULL;   // black gamma (e.g. exp=1.4) | 
 | 245 |     tables[1] = NULL;   // white gamma (e.g. exp= 1/1.4) | 
 | 246 | } | 
 | 247 |  | 
 | 248 | // static | 
 | 249 | SkAdvancedTypefaceMetrics* SkFontHost::GetAdvancedTypefaceMetrics( | 
 | 250 |                                                                   uint32_t fontID, | 
 | 251 |                                                                   SkAdvancedTypefaceMetrics::PerGlyphInfo perGlyphInfo) { | 
| mtklein@google.com | 330313a | 2013-08-22 15:37:26 +0000 | [diff] [blame] | 252 |     SkDEBUGFAIL("SkFontHost::GetAdvancedTypefaceMetrics unimplemented"); | 
| yangsu@google.com | 1a2b4c1 | 2011-06-24 17:20:50 +0000 | [diff] [blame] | 253 |     return NULL; | 
 | 254 | } | 
 | 255 |  | 
| bungeman@google.com | cb1bbb3 | 2012-10-12 18:48:35 +0000 | [diff] [blame] | 256 | void SkFontHost::FilterRec(SkScalerContext::Rec* rec, SkTypeface*) { | 
| yangsu@google.com | 1a2b4c1 | 2011-06-24 17:20:50 +0000 | [diff] [blame] | 257 | } | 
 | 258 |  | 
 | 259 | SkScalerContext* SkFontHost::CreateScalerContext(const SkDescriptor* desc) { | 
| mtklein@google.com | 330313a | 2013-08-22 15:37:26 +0000 | [diff] [blame] | 260 |     SkDEBUGFAIL("SkFontHost::CreateScalarContext unimplemented"); | 
| yangsu@google.com | 1a2b4c1 | 2011-06-24 17:20:50 +0000 | [diff] [blame] | 261 |     return NULL; | 
 | 262 | } |