3 import "fontManagement"
5 #if (defined(ECERE_VANILLA) || defined(ECERE_ONEDRIVER)) && defined(__WIN32__)
6 #define ECERE_NOTRUETYPE
13 #define strlen _strlen
14 #if !defined(ECERE_NOTRUETYPE)
16 #include FT_FREETYPE_H
17 #include FT_TRUETYPE_TABLES_H
18 #include FT_UNPATENTED_HINTING_H
19 #define property _property
26 #if !defined(ECERE_NOTRUETYPE)
27 static int utf16BufferSize = 0;
28 static uint16 * utf16 = null;
31 #if !defined(ECERE_NOTRUETYPE)
33 #if !defined(ECERE_VANILLA)
39 #define MAX_FONT_LINK_ENTRIES 10
41 static HB_Script theCurrentScript;
43 static unichar UTF16GetChar(const uint16 *string, int * nw)
46 if(HB_IsHighSurrogate(string[0]) && HB_IsLowSurrogate(string[1]))
48 ch = HB_SurrogateToUcs4(string[0], string[1]);
59 static HB_Bool hb_stringToGlyphs(HB_Font font, const uint16 * string, uint length, HB_Glyph *glyphs, uint *numGlyphs, HB_Bool rightToLeft)
61 FT_Face face = ((FontEntry)font->userData).face;
65 if (length > *numGlyphs)
68 for (c = 0; c < length; c += nw)
70 unichar ch = UTF16GetChar(string + c, &nw);
71 glyphs[glyph_pos++] = FT_Get_Char_Index(face, ch);
73 *numGlyphs = glyph_pos;
77 static void hb_getAdvances(HB_Font font, const HB_Glyph * glyphs, uint numGlyphs, HB_Fixed *advances, int flags)
79 FontEntry entry = font->userData;
80 Font glFont = entry.font;
83 GlyphPack pack = glFont.asciiPack;
85 for(fontEntryNum = 0; fontEntryNum < MAX_FONT_LINK_ENTRIES; fontEntryNum++)
87 if(glFont.fontEntries[fontEntryNum] == entry)
91 for(c = 0; c < numGlyphs; c++)
94 uint glyphNo = glyphs[c] | 0x80000000 | (theCurrentScript << 24);
95 uint packNo = glyphNo & 0xFFFFFF80;
96 if(packNo != lastPack)
98 pack = (GlyphPack)glFont.glyphPacks.Find((uintptr)packNo);
101 glFont.glyphPacks.Add((pack = GlyphPack { key = (uintptr)packNo }));
102 pack.Render(glFont, fontEntryNum, glFont.displaySystem);
106 glyph = &pack.glyphs[glyphNo & 0x7F];
107 advances[c] = glyph->ax;
111 static HB_Bool hb_canRender(HB_Font font, const uint16 * string, uint length)
113 FT_Face face = ((FontEntry)font->userData).face;
116 for (c = 0; c < length; c += nw)
118 unichar ch = UTF16GetChar(string + c, &nw);
119 if(!FT_Get_Char_Index(face, ch))
125 static HB_Error hb_getSFntTable(void *font, HB_Tag tableTag, HB_Byte *buffer, HB_UInt *length)
127 FT_Face face = (FT_Face)font;
128 FT_ULong ftlen = *length;
131 if (!FT_IS_SFNT(face))
132 return HB_Err_Invalid_Argument;
134 error = FT_Load_Sfnt_Table(face, tableTag, 0, buffer, &ftlen);
135 *length = (uint)ftlen;
136 return (HB_Error)error;
139 static HB_Error hb_getPointInOutline(HB_Font font, HB_Glyph glyph, int flags, hb_uint32 point, HB_Fixed *xpos, HB_Fixed *ypos, hb_uint32 *nPoints)
141 HB_Error error = HB_Err_Ok;
142 FT_Face face = (FT_Face)font->userData;
144 int load_flags = (flags & HB_ShaperFlag_UseDesignMetrics) ? FT_LOAD_NO_HINTING : FT_LOAD_DEFAULT;
146 if ((error = (HB_Error)FT_Load_Glyph(face, glyph, load_flags)))
149 if (face->glyph->format != ft_glyph_format_outline)
150 return (HB_Error)HB_Err_Invalid_SubTable;
152 *nPoints = face->glyph->outline.n_points;
156 if (point > *nPoints)
157 return (HB_Error)HB_Err_Invalid_SubTable;
159 *xpos = (int)face->glyph->outline.points[point].x;
160 *ypos = (int)face->glyph->outline.points[point].y;
165 static void hb_getGlyphMetrics(HB_Font font, HB_Glyph theGlyph, HB_GlyphMetrics *metrics)
167 FontEntry entry = font->userData;
168 Font glFont = entry.font;
170 GlyphPack pack = glFont.asciiPack;
172 for(fontEntryNum = 0; fontEntryNum < MAX_FONT_LINK_ENTRIES; fontEntryNum++)
174 if(glFont.fontEntries[fontEntryNum] == entry)
179 uint glyphNo = theGlyph | 0x80000000 | (theCurrentScript << 24);
180 uint packNo = glyphNo & 0xFFFFFF80;
181 if(packNo != lastPack)
183 pack = (GlyphPack)glFont.glyphPacks.Find((uintptr)packNo);
186 pack = { key = (uintptr)packNo };
187 glFont.glyphPacks.Add(pack);
188 pack.Render(glFont, fontEntryNum, glFont.displaySystem);
192 glyph = &pack.glyphs[glyphNo & 0x7F];
194 metrics->x = glyph->ax;
196 metrics->width = glyph->w;
197 metrics->height = glyph->h;
198 metrics->xOffset = glyph->bx;
199 metrics->yOffset = glyph->by;
203 static HB_Fixed hb_getFontMetric(HB_Font font, HB_FontMetric metric)
205 FontEntry entry = font->userData;
206 FT_Face face = entry.face;
208 // Note that we aren't scanning the VDMX table which we probably would in
210 if(metric == HB_FontAscent)
211 return face->ascender;
215 static HB_FontClass hb_fontClass =
217 hb_stringToGlyphs, hb_getAdvances, hb_canRender,
218 hb_getPointInOutline, hb_getGlyphMetrics, hb_getFontMetric
221 static uint FT_stream_load(FT_Stream stream, long offset, byte * buffer, long count)
223 File f = stream->descriptor.pointer;
224 f.Seek((int)offset, start);
225 return count ? f.Read(buffer, 1, (uint)count) : 0;
228 static void FT_stream_close(FT_Stream stream)
230 File f = stream->descriptor.pointer;
235 static FT_Library ftLibrary;
238 static BinaryTree loadedFonts
240 CompareKey = (void *)BinaryTree::CompareString
243 class FontEntry : BTNode
252 //If we don't save the FT_Stream before sacrificing it to FreeType, the garbage collector (if one is used) will destroy it prematurely
269 FT_Done_FreeType(ftLibrary);
275 FontEntry ::Load(FaceInfo info)
277 FontEntry fontEntry = (FontEntry)loadedFonts.FindString(info.fileName);
280 File file = FileOpen/*Buffered*/(info.fileName, read);
283 FileSize fileSize = file.GetSize();
284 FT_Open_Args args = { 0 };
285 FT_Parameter param = { FT_PARAM_TAG_UNPATENTED_HINTING };
286 FT_Stream stream = new0 FT_StreamRec[1];
289 FT_Init_FreeType( &ftLibrary );
291 fontEntry = FontEntry { key = (uintptr)CopyString(info.fileName) };
292 fontEntry.stream = stream;
295 fontEntry.buffer = new byte[fileSize];
296 file.Read(fontEntry.buffer, 1, fileSize);
299 //args.num_params = 1;
300 args.params = ¶m;
302 stream->size = fileSize;
303 stream->descriptor.pointer = file;
304 stream->read = FT_stream_load;
305 stream->close = FT_stream_close;
307 args.flags = /*FT_OPEN_PATHNAME|*//*FT_OPEN_MEMORY|*/FT_OPEN_STREAM/*|FT_OPEN_PARAMS*/;
308 args.stream = stream;
309 //args.pathname = fileName;
310 //args.memory_base = fontEntry.buffer;
311 //args.memory_size = fileSize;
313 // printf("Opening: %s\n", fileName);
314 FT_Open_Face( ftLibrary, &args, info.fontID, &fontEntry.face );
319 fontEntry.hbFace = HB_NewFace(fontEntry.face, hb_getSFntTable);
320 fontEntry.hbFont.klass = &hb_fontClass;
321 fontEntry.hbFont.userData = fontEntry; //.face;
324 loadedFonts.Add(fontEntry);
329 // printf("Error opening font %s\n", fileName);
337 static float FaceSetCharSize(FT_Face face, float size)
340 if(FT_Set_Char_Size(face, (int)(size * 64), (int)(size * 64), 96, 96))
342 if(face->num_fixed_sizes)
345 int bestDiff = MAXINT, best = 0;
346 FT_Bitmap_Size * sizes = face->available_sizes;
347 int wishedHeight = (int)(size * 96 / 72);
348 for(c = 0; c < face->num_fixed_sizes; c++)
350 int diff = abs(sizes[c].height - wishedHeight);
357 FT_Set_Pixel_Sizes(face, sizes[best].width, sizes[best].height);
360 face->ascender = sizes[best].height;
361 scale = (float)wishedHeight / sizes[best].height;
373 int ox, oy; // Outline
381 class GlyphPack : BTNode
384 Bitmap bitmap { transparent = true, alphaBlend = true };
386 int cellWidth, cellHeight;
387 int oCellWidth, oCellHeight;
394 void Render(Font font, int startFontEntry, DisplaySystem displaySystem)
396 #if !defined(ECERE_NOTRUETYPE)
398 int maxWidth = 0, maxHeight = 0;
399 int cellWidth, cellHeight;
400 int oCellWidth = 0, oCellHeight = 0;
401 int width, height, oWidth = 0, oHeight = 0;
402 FontEntry fontEntry = null;
405 float outlineSize = font.outlineSize;
406 int padding = 1 + (int)outlineSize;
407 bool isGlyph = ((uint)key & 0x80000000) != 0;
408 unichar testChar = 0;
409 Bitmap bitmap = this.bitmap;
411 for(c = 0; c < MAX_FONT_LINK_ENTRIES; c++)
413 fontEntry = font.fontEntries[c];
417 FT_Vector pen = { 0, 0 };
421 matrix.xx = (FT_Fixed)( 1.0 * 0x10000L );
422 matrix.xy = (FT_Fixed)( 0.3 * 0x10000L );
423 matrix.yx = (FT_Fixed)( 0.0 * 0x10000L );
424 matrix.yy = (FT_Fixed)( 1.0 * 0x10000L );
425 FT_Set_Transform(fontEntry.face, &matrix, &pen);
427 fontEntry.scale = FaceSetCharSize(fontEntry.face, font.size);
429 font.scale = fontEntry.scale;
432 if(!fontEntry.face->units_per_EM)
434 font.ascent = (int)((double)fontEntry.face->ascender);
435 font.descent = (int)((double)fontEntry.face->descender);
439 font.ascent = (int)((double)fontEntry.face->ascender * fontEntry.face->size->metrics.y_ppem / fontEntry.face->units_per_EM);
440 font.descent = (int)((double)fontEntry.face->descender * fontEntry.face->size->metrics.y_ppem / fontEntry.face->units_per_EM);
444 fontEntry.hbFont.x_ppem = fontEntry.face->size->metrics.x_ppem;
445 fontEntry.hbFont.y_ppem = fontEntry.face->size->metrics.y_ppem;
446 fontEntry.hbFont.x_scale = (int)fontEntry.face->size->metrics.x_scale;
447 fontEntry.hbFont.y_scale = (int)fontEntry.face->size->metrics.y_scale;
452 for(c = 0; c < 128; c++)
457 uint glyph = ((uint)key | c) & 0xFFFFFF;
458 for(entry = startFontEntry; entry < MAX_FONT_LINK_ENTRIES; entry++)
460 fontEntry = font.fontEntries[entry];
461 if(fontEntry && (FT_Get_Char_Index(fontEntry.face, testChar) || !testChar || entry == MAX_FONT_LINK_ENTRIES-1 || !font.fontEntries[entry+1]))
463 if(!FT_Load_Glyph(fontEntry.face, glyph, FT_LOAD_DEFAULT /*FT_LOAD_NO_HINTING*/) || entry == MAX_FONT_LINK_ENTRIES-1 || !font.fontEntries[entry+1])
465 //printf("%s: Accepted entry %d ", faceName, entry);
473 for(entry = startFontEntry; entry < MAX_FONT_LINK_ENTRIES; entry++)
476 fontEntry = font.fontEntries[entry];
477 if(fontEntry && ((glyph = FT_Get_Char_Index(fontEntry.face, ((uint)key | c) & 0xFFFFFF)) || entry == MAX_FONT_LINK_ENTRIES-1 || !font.fontEntries[entry+1]))
479 if(!FT_Load_Glyph(fontEntry.face, glyph, FT_LOAD_DEFAULT /*FT_LOAD_NO_HINTING*/) || entry == MAX_FONT_LINK_ENTRIES-1 || !font.fontEntries[entry+1])
484 scales[c] = fontEntry ? fontEntry.scale : 0;
485 faces[c] = fontEntry ? fontEntry.face : null;
488 maxWidth = Max(maxWidth, ((faces[c]->glyph->metrics.width + 64 + (64 - (faces[c]->glyph->metrics.width & 0x3F))) >> 6));
489 maxHeight = Max(maxHeight, ((faces[c]->glyph->metrics.height + 64 + (64 - (faces[c]->glyph->metrics.height & 0x3F))) >> 6));
492 this.cellWidth = cellWidth = maxWidth;
493 this.cellHeight = cellHeight = maxHeight;
495 width = pow2i(maxWidth * 16);
496 height = pow2i(maxHeight * 8);
498 #if !defined(ECERE_VANILLA)
501 oCellWidth = 2*padding + cellWidth;
502 oCellHeight = 2*padding + cellHeight;
503 oWidth = pow2i(oCellWidth * 16);
504 oHeight = pow2i(oCellHeight * 8);
505 outline = { transparent = true, alphaBlend = true };
509 if(bitmap.Allocate(null, width, height, 0, pixelFormatAlpha, false) &&
510 (!outline || outline.Allocate(null, oWidth, oHeight, 0, pixelFormatAlpha, false)))
512 float fade = font.outlineFade;
513 float alphaFactor = 1.0f / (0.2f + fade);
514 // float intensityFactor = 1.0f / (0.2f + outlineSize);
515 float range = outlineSize, rangeInv = 1.0f / range;
516 float * distanceMap = null;
517 byte * padded = null;
520 distanceMap = new float[oCellWidth * oCellHeight];
521 padded = new byte[oCellWidth * oCellHeight];
524 for(c = 0; c < 128; c++)
528 int gx = ((uint)c & 0xF), gy = ((uint)c >> 4);
529 int sx = gx * cellWidth, sy = gy * cellHeight;
530 byte * picture = (byte *)bitmap.picture;
531 Glyph * glyph = &glyphs[c];
532 FT_GlyphSlot slot = null;
533 int glyphNo = isGlyph ? (((uint)key | c) & 0x00FFFFFF) : (faces[c] ? FT_Get_Char_Index(faces[c], (uint)key | c) : 0);
536 double em_size = 1.0 * faces[c]->units_per_EM;
537 double y_scale = em_size ? (faces[c]->size->metrics.y_ppem / em_size) : 1;
538 double ascender = faces[c]->ascender * y_scale;
539 slot = faces[c]->glyph;
541 FT_Load_Glyph(faces[c], glyphNo, /*FT_LOAD_DEFAULT | FT_LOAD_FORCE_AUTOHINT*/ FT_LOAD_DEFAULT /*FT_LOAD_NO_HINTING*/); // FT_LOAD_RENDER // FT_LOAD_NO_HINTING
543 FT_Render_Glyph(slot, FT_RENDER_MODE_NORMAL);
545 glyph->left = slot->bitmap_left;
546 glyph->top = (int)(ascender - slot->bitmap_top) + (int)(font.height - (faces[c]->size->metrics.height >> 6)) / 2;
548 xMax = sx + slot->bitmap.width;
549 yMax = sy + slot->bitmap.rows;
554 if(slot->bitmap.pixel_mode != FT_PIXEL_MODE_MONO)
556 for(j = sy, q = 0; j<yMax; j++)
558 for(p = 0, i = sx; i<xMax; i++)
560 byte value = ((byte *)slot->bitmap.buffer)[q + p++];
567 q += slot->bitmap.pitch;
571 for(j = sy, q = 0; j<yMax; j++)
574 for(p = 0, i = sx; i<xMax; i++)
576 if(slot->bitmap.pixel_mode == FT_PIXEL_MODE_MONO)
578 picture[j * bitmap.stride + i] = (slot->bitmap.buffer[q + p] & bit) ? 255 : 0;
580 if(!bit) { bit = 0x80; p++; }
584 byte value = ((byte *)slot->bitmap.buffer)[q + p++];
585 picture[j * bitmap.stride + i] = value;
588 q += slot->bitmap.pitch;
591 #if !defined(ECERE_VANILLA)
594 // Generate outline from distance map
595 float * dmap = distanceMap;
596 byte *dst = outline.picture + gy * oCellHeight * oWidth + gx * oCellWidth;
598 byte * core = picture + gy * cellHeight * width + gx * cellWidth, * p;
599 memset(padded, 0, oCellWidth * oCellHeight);
600 if(slot->bitmap.width)
602 byte * src = padded + padding * oCellWidth + padding;
604 for(y = 0; y < cellHeight; y++)
606 byte * pic = picture;
608 for(x = 0; x < cellWidth; x++, p++, pic++)
614 imgDistMapBuild(distanceMap, padded, oCellWidth, oCellHeight, 1, oCellWidth);
616 //core -= padding * width;
617 for(y = 0; y < oCellHeight; y++, dst += oWidth)
621 for(x = 0; x < oCellWidth; x++, dstRow++, dmap++, p++)
623 float rangeBase = (range - *dmap) * rangeInv, alpha = alphaFactor * rangeBase;
624 *dstRow = (byte)( Max( 0.0f, Min( 255.0f, alpha * 255.0f ) ) + 0.5f);
626 if(y >= padding && y < cellWidth + padding && x >= padding && x < cellWidth + padding)
628 float intensity = Max( (float) *p * (1.0f/255.0f), intensityFactor * rangeBase );
629 byte v = (byte)( Max( 0.0f, Min( 255.0f, intensity * 255.0f ) ) + 0.5f);
637 glyph->ox = gx * oCellWidth;
638 glyph->oy = gy * oCellHeight;
646 glyph->w = slot->bitmap.width;
647 glyph->h = slot->bitmap.rows;
648 glyph->ax = (int)slot->advance.x;
649 glyph->ay = (int)(slot->advance.y + (64 - slot->advance.y % 64));
651 glyph->glyphNo = glyphNo;
654 glyph->bx = (int)faces[c]->glyph->metrics.horiBearingX;
655 glyph->by = (int)faces[c]->glyph->metrics.horiBearingY;
657 glyph->scale = scales[c];
668 for(c = 0; c<256; c++)
669 bitmap.palette[c] = ColorAlpha { 255, { (byte)c,(byte)c,(byte)c } };
670 bitmap.pixelFormat = pixelFormat8;
672 sprintf(fileName, "font%d", fid);
673 ChangeExtension(fileName, "pcx", fileName);
675 bitmap.Save(fileName, null, 0);
676 bitmap.pixelFormat = pixelFormatAlpha;
680 for(c = 0; c<256; c++)
681 outline.palette[c] = ColorAlpha { 255, { (byte)c,(byte)c,(byte)c } };
682 outline.pixelFormat = pixelFormat8;
684 sprintf(fileName, "outline%d", fid);
685 ChangeExtension(fileName, "pcx", fileName);
687 outline.Save(fileName, null, 0);
688 outline.pixelFormat = pixelFormatAlpha;
694 if(displaySystem && displaySystem.pixelFormat != pixelFormat4) // TODO: Add none PixelFormat
696 displaySystem.Lock();
697 #if defined(__WIN32__)
698 // Is this check still required?
699 if(displaySystem.driver == class(OpenGLDisplayDriver)
701 #if !defined(_GLES) && !defined(ECERE_STATIC)
702 || displaySystem.driver == class(Direct3D8DisplayDriver)
703 || displaySystem.driver == class(Direct3D9DisplayDriver)
708 #if !defined(ECERE_VANILLA)
709 if(displaySystem.driver == class(OpenGLDisplayDriver) && lastBlitTex)
712 bitmap.MakeDD(displaySystem);
714 outline.MakeDD(displaySystem);
715 #if !defined(ECERE_VANILLA)
716 if(displaySystem.driver == class(OpenGLDisplayDriver) && lastBlitTex)
717 GLBegin(GLIMTKMode::quads);
720 displaySystem.Unlock();
727 #if !defined(ECERE_NOTRUETYPE)
728 static HB_ShaperItem shaper_item;
730 static uint * shaping(FontEntry entry, uint16 * string, int len, HB_Script script, int *numGlyphs, bool * rightToLeft)
732 static uint maxGlyphs = 0;
733 HB_Glyph * glyphs = shaper_item.glyphs;
735 shaper_item.kerning_applied = 0;
736 shaper_item.string = string;
737 shaper_item.stringLength = len;
738 shaper_item.item.script = script;
739 shaper_item.item.pos = 0;
740 shaper_item.item.length = shaper_item.stringLength;
741 if(script == HB_Script_Arabic || script == HB_Script_Hebrew || script == HB_Script_Thaana || script == HB_Script_Syriac)
742 shaper_item.item.bidiLevel = 1;
744 shaper_item.item.bidiLevel = 0;
745 shaper_item.shaperFlags = 0;
746 shaper_item.font = &entry.hbFont;
747 shaper_item.face = entry.hbFace;
748 shaper_item.num_glyphs = shaper_item.item.length;
749 shaper_item.glyphIndicesPresent = 0;
750 shaper_item.initialGlyphCount = 0;
751 shaper_item.num_glyphs = 0;
752 shaper_item.glyphs = null;
754 while(!HB_ShapeItem(&shaper_item))
756 if(shaper_item.num_glyphs > maxGlyphs)
758 maxGlyphs = shaper_item.num_glyphs;
759 glyphs = shaper_item.glyphs = renew0 glyphs HB_Glyph[maxGlyphs];
760 shaper_item.attributes = renew0 shaper_item.attributes HB_GlyphAttributes[maxGlyphs];
761 shaper_item.advances = renew0 shaper_item.advances HB_Fixed[maxGlyphs];
762 shaper_item.offsets = renew0 shaper_item.offsets HB_FixedPoint[maxGlyphs];
763 shaper_item.log_clusters = renew0 shaper_item.log_clusters unsigned short[maxGlyphs];
767 shaper_item.glyphs = glyphs;
768 shaper_item.num_glyphs = maxGlyphs;
772 *numGlyphs = shaper_item.num_glyphs;
773 *rightToLeft = (bool)(shaper_item.item.bidiLevel % 2);
774 return shaper_item.glyphs;
778 delete shaper_item.glyphs;
779 delete shaper_item.attributes;
780 delete shaper_item.advances;
781 delete shaper_item.offsets;
782 delete shaper_item.log_clusters;
786 public class Font : struct
796 BinaryTree glyphPacks { };
797 GlyphPack asciiPack { };
800 DisplaySystem displaySystem;
802 #if !defined(ECERE_NOTRUETYPE)
803 FontEntry fontEntries[MAX_FONT_LINK_ENTRIES];
808 #if !defined(ECERE_NOTRUETYPE)
812 while((pack = (GlyphPack)glyphPacks.root))
814 glyphPacks.Remove(pack);
818 for(entry = 0; entry<MAX_FONT_LINK_ENTRIES; entry++)
820 FontEntry fontEntry = fontEntries[entry];
826 loadedFonts.Remove(fontEntry);
833 public property int ascent
835 get { return (int)(this ? ascent * scale : 0); }
837 public property int descent
839 get { return (int)(this ? descent * scale : 0); }
842 void Setup(DisplaySystem displaySystem, const String faceName, float size, FontFlags flags, float outlineSize, float outlineFade)
844 strcpy(this.faceName, faceName);
846 this.displaySystem = displaySystem;
848 this.outlineSize = outlineSize;
849 this.outlineFade = outlineFade;
852 bool LoadEntry(FaceInfo info)
855 #if !defined(ECERE_NOTRUETYPE)
856 if(numEntries < MAX_FONT_LINK_ENTRIES)
858 FontEntry fontEntry = FontEntry::Load(info);
864 FT_Vector pen = { 0, 0 };
867 matrix.xx = (FT_Fixed)( 1.0 * 0x10000L );
868 matrix.xy = (FT_Fixed)( 0.3 * 0x10000L );
869 matrix.yx = (FT_Fixed)( 0.0 * 0x10000L );
870 matrix.yy = (FT_Fixed)( 1.0 * 0x10000L );
874 matrix.xx = (FT_Fixed)( 1.0 * 0x10000L );
875 matrix.xy = (FT_Fixed)( 0.0 * 0x10000L );
876 matrix.yx = (FT_Fixed)( 0.0 * 0x10000L );
877 matrix.yy = (FT_Fixed)( 1.0 * 0x10000L );
879 FT_Set_Transform(fontEntry.face, &matrix, &pen );
880 FaceSetCharSize(fontEntry.face, size);
881 height = (int)((fontEntry.face->size->metrics.height) >> 6); //* y_scale;
883 height = size * 96 / 72 + 4;
884 // printf("Font height is %d\n", height);
885 this.fakeItalic = info.fakeItalic;
887 fontEntries[numEntries++] = fontEntry;
897 Font ::Load(DisplaySystem displaySystem, const char * faceName, float size, FontFlags flags, float outlineSize, float outlineFade)
900 Array<FaceInfo> infos = ResolveFont(faceName, size, flags);
904 bool success = false;
905 font.Setup(displaySystem, faceName, size, flags, outlineSize, outlineFade);
907 success |= font.LoadEntry(f);
910 font.asciiPack.Render(font, 0, displaySystem);
921 void ProcessString(DisplaySystem displaySystem, const byte * text, int len,
923 Surface surface, Display display, int * x, int y, int prevGlyph, int * rPrevGlyph, int * advance)
925 #if !defined(ECERE_NOTRUETYPE)
926 if(this && fontEntries[0])
928 LFBSurface lfbSurface = surface ? surface.driverData : null;
929 int previousGlyph = prevGlyph;
930 FT_Face previousFace = 0;
931 int c, nb, glyphIndex = 0;
932 bool writingOutline = lfbSurface && lfbSurface.writingOutline;
933 int padding = writingOutline ? 1 + (int)surface.font.outlineSize : 0;
934 unichar lastPack = writingOutline ? -1 : 0;
935 GlyphPack pack = asciiPack;
936 Bitmap bitmap = writingOutline ? pack.outline : pack.bitmap;
938 uint * glyphs = null;
940 bool rightToLeft = false;
941 int fontEntryNum = 0;
943 FontEntry curFontEntry;
944 Glyph * lastGlyph = null;
947 for(c = 0; c < len || (numGlyphs && (rightToLeft ? (glyphIndex >= 0) : (glyphIndex < numGlyphs)));)
951 if(numGlyphs && (rightToLeft ? (glyphIndex >= 0) : (glyphIndex < numGlyphs)))
953 glyphNo = glyphs[glyphIndex] | 0x80000000 | (glyphScript << 24);
954 rightToLeft ? glyphIndex-- : glyphIndex++;
958 HB_Script curScript = HB_Script_Common;
959 const byte * scriptStart = text + c;
960 //unichar nonASCIIch = 0;
963 unichar testChar = 0;
964 const String testLang = null;
968 HB_Script script = HB_Script_Common;
969 ch = UTF8GetChar((const char *)text + c, &nb);
970 //if(ch > 127) nonASCIIch = ch;
972 if(ch == 32 && curScript)
979 for(a = c + 1; a < c + len; a++)
987 unichar ahead = UTF8GetChar((const char *)text + a, &nb);
988 if((ahead >= 0x590 && ahead <= 0x7C0) || (ahead >= 0xFB1D && ahead <= 0xFB4F) || (ahead >= 0xFB50 && ahead <= 0xFDFF))
996 script = HB_Script_Common;
997 else if(ch <= 0x11FF)
1001 case 0x300: script = HB_Script_Greek; break;
1002 case 0x400: script = HB_Script_Cyrillic; break;
1003 case 0x500: script = (ch < 0x530) ? HB_Script_Cyrillic : ((ch < 0x590) ? HB_Script_Armenian : HB_Script_Hebrew); break;
1004 case 0x600: script = HB_Script_Arabic; break;
1005 case 0x700: script = (ch < 0x750) ? HB_Script_Syriac : ((ch < 0x780) ? HB_Script_Arabic : ((ch < 0x7C0) ? HB_Script_Thaana : HB_Script_Common)); break;
1006 case 0x800: script = HB_Script_Common; break; // NO CHARACTERS ASSIGNED BETWEEN 0x7C0 and 0x8FF?
1007 case 0x900: script = (ch < 0x980) ? HB_Script_Devanagari : HB_Script_Bengali; break;
1008 case 0xA00: script = (ch < 0xA80) ? HB_Script_Gurmukhi : HB_Script_Gujarati; break;
1009 case 0xB00: script = (ch < 0xB80) ? HB_Script_Oriya : HB_Script_Tamil; break;
1010 case 0xC00: script = (ch < 0xC80) ? HB_Script_Telugu : HB_Script_Kannada; break;
1011 case 0xD00: script = (ch < 0xD80) ? HB_Script_Malayalam : HB_Script_Sinhala; break;
1012 case 0xE00: script = (ch < 0xE80) ? HB_Script_Thai : HB_Script_Lao; break;
1013 case 0xF00: script = HB_Script_Tibetan; break;
1014 case 0x1000: script = (ch < 0x10A0) ? HB_Script_Myanmar : HB_Script_Georgian; break;
1015 case 0x1100: script = HB_Script_Hangul; break;
1018 else if(ch >= 0x1F00 && ch <= 0x1FFF) script = HB_Script_Greek;
1019 else if((ch >= 0x2D00 && ch <= 0x2D2F) || (ch >= 0x3130 && ch <= 0x318F) || (ch >= 0xAC00 && ch <= 0xD7AF) || (ch >= 0xFFA0 && ch <= 0xFFDC))
1020 script = HB_Script_Hangul;
1021 else if(ch >= 0x1680 && ch <= 0x169F) script = HB_Script_Ogham;
1022 else if(ch >= 0x16A0 && ch <= 0x16FF) script = HB_Script_Runic;
1023 else if((ch >= 0x1780 && ch <= 0x17FF) || (ch >= 0x19E0 && ch <= 0x19FF)) script = HB_Script_Khmer;
1024 else if(ch >= 0x3040 && ch <= 0x309F) script = 60;
1025 else if(ch >= 0x3400 && ch <= 0x9FBF) script = 61;
1026 //else if(ch >= 0x4E00 && ch <= 0x9FBF) script = 61;
1027 else if(ch >= 0xFB13 && ch <= 0xFB17) script = HB_Script_Armenian;
1028 else if(ch >= 0xFB1D && ch <= 0xFB4F) script = HB_Script_Hebrew;
1029 else if(ch >= 0xFB50 && ch <= 0xFDFF) script = HB_Script_Arabic;
1032 if(!script || (script != curScript))
1040 if(!script || script > HB_ScriptCount) { c += nb; if(script > HB_ScriptCount) curScript = script; break; }
1041 if(!script) { c += nb; break; }
1048 if(curScript == HB_Script_Common || curScript > HB_ScriptCount)
1050 rightToLeft = false;
1052 theCurrentScript = 0;
1056 int len = c - (int)(scriptStart - text);
1057 int max = len * 2 + 1;
1058 if(max > utf16BufferSize)
1060 utf16 = renew utf16 uint16[max];
1061 utf16BufferSize = max;
1063 wc = UTF8toUTF16BufferLen((const char *)scriptStart, utf16, max, len);
1064 theCurrentScript = glyphScript = curScript;
1068 case HB_Script_Arabic: testChar = 0x621; /*testLang = "ar"; */
1069 //printf("Arabic ");
1071 case HB_Script_Devanagari: testChar = 0x905;
1073 //printf("Devanagari ");
1075 case HB_Script_Hebrew: testChar = 0x05EA /*'ת'*/; /*testLang = "he"; */
1076 //printf("Hebrew ");
1079 testChar = (ch == '\t') ? ' ' : ch;
1081 case 60: testChar = 'あ'; break;
1082 case 61: testChar = 0x3400; break; //'愛'; break;
1088 // printf("Testing for char %x\n", testChar);
1089 for(fontEntryNum = 0; fontEntryNum<MAX_FONT_LINK_ENTRIES; fontEntryNum++)
1091 if(fontEntries[fontEntryNum] && FT_Get_Char_Index(fontEntries[fontEntryNum].face, testChar))
1093 /*if(fontEntries[fontEntryNum])
1094 printf("Not found in %s\n", (char *)fontEntries[fontEntryNum].key);*/
1098 if(fontEntryNum == MAX_FONT_LINK_ENTRIES)
1101 // Do we still have room to add an entry?
1102 for(fontEntryNum = 0; fontEntryNum<MAX_FONT_LINK_ENTRIES; fontEntryNum++)
1103 if(!fontEntries[fontEntryNum])
1105 if(fontEntryNum == MAX_FONT_LINK_ENTRIES)
1108 if((info = ResolveCharFont(faceName, size, flags, testLang, testChar)))
1110 FontEntry fontEntry = FontEntry::Load(info);
1113 FaceSetCharSize(fontEntry.face, size);
1114 fontEntries[fontEntryNum] = fontEntry;
1120 if(!fontEntries[fontEntryNum])
1123 if(curScript > HB_ScriptCount) curScript = HB_Script_Common;
1124 if(curScript != HB_Script_Common && curScript < HB_ScriptCount)
1126 fontEntries[fontEntryNum].font = this;
1127 glyphs = shaping(fontEntries[fontEntryNum], utf16, wc, curScript, &numGlyphs, &rightToLeft);
1131 glyphIndex = rightToLeft ? (numGlyphs - 1) : 0;
1132 glyphNo = glyphs[glyphIndex] | 0x80000000 | (glyphScript << 24);
1133 rightToLeft ? glyphIndex-- : glyphIndex++;
1137 curFontEntry = fontEntries[fontEntryNum];
1139 packNo = glyphNo & 0xFFFFFF80;
1141 if(packNo != lastPack)
1147 pack = (GlyphPack)glyphPacks.Find((uintptr)packNo);
1150 pack = GlyphPack { key = (uintptr)packNo };
1151 glyphPacks.Add(pack);
1152 pack.Render(this, fontEntryNum, displaySystem);
1155 bitmap = writingOutline ? pack.outline : pack.bitmap;
1160 FT_Face face = curFontEntry ? curFontEntry.face : null;
1161 int index = rightToLeft ? (glyphIndex + 1) : (glyphIndex-1);
1162 Glyph * glyph = &pack.glyphs[glyphNo & 0x7F];
1164 int ax = (int)((numGlyphs ? shaper_item.advances[index] : glyph->ax) * glyph->scale);
1165 int offset = numGlyphs ? shaper_item.offsets[index].x : 0;
1169 if(previousGlyph && curFontEntry && (face == previousFace || !previousFace)) // TO IMPROVE: Assuming same face for now for multiple calls...
1171 FT_Vector delta = { 0, 0 };
1172 FT_Get_Kerning(curFontEntry.face, previousGlyph, glyph->glyphNo, FT_KERNING_UNFITTED, &delta );
1173 if(delta.x < 0) delta.x += (-delta.x) % 64;
1174 else if(delta.x) delta.x += 64 - (delta.x % 64);
1175 *x += delta.x * glyph->scale;
1177 else if(curFontEntry)
1178 FaceSetCharSize(face, size);
1180 previousGlyph = glyph->glyphNo;
1181 previousFace = face;
1185 int h = (int)face->size->metrics.height;
1186 int desc = (int)face->size->metrics.descender;
1187 int oy = (numGlyphs ? shaper_item.offsets[index].y : 0);
1191 oy += h + desc - glyph->by;
1195 surface.driver.Blit(display, surface, bitmap, ((*x) >> 6) + glyph->left - writingOutline * padding, y + oy - writingOutline * padding,
1196 writingOutline ? glyph->ox : glyph->x, writingOutline ? glyph->oy : glyph->y, glyph->w + writingOutline + 2 * padding, glyph->h + writingOutline + 2 * padding);
1203 if(numGlyphs && (rightToLeft ? (glyphIndex < 0) : (glyphIndex == numGlyphs)))
1208 int w = (lastGlyph->w + lastGlyph->left) * (1 << 6);
1209 // Fix for advance != width + left (e.g. italic fonts)
1210 if(w > lastAX && advance)
1211 *advance = w - lastAX;
1213 if(rPrevGlyph) *rPrevGlyph = previousGlyph;
1215 lfbSurface.xOffset = 0;