| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415 |
- // Copyright (C) 2004-2025 Artifex Software, Inc.
- //
- // This file is part of MuPDF.
- //
- // MuPDF is free software: you can redistribute it and/or modify it under the
- // terms of the GNU Affero General Public License as published by the Free
- // Software Foundation, either version 3 of the License, or (at your option)
- // any later version.
- //
- // MuPDF is distributed in the hope that it will be useful, but WITHOUT ANY
- // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- // FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
- // details.
- //
- // You should have received a copy of the GNU Affero General Public License
- // along with MuPDF. If not, see <https://www.gnu.org/licenses/agpl-3.0.en.html>
- //
- // Alternative licensing terms are available from the licensor.
- // For commercial licensing, see <https://www.artifex.com/> or contact
- // Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco,
- // CA 94129, USA, for further information.
- #include "mupdf/fitz.h"
- #include "mupdf/ucdn.h"
- #include "draw-imp.h"
- #include "color-imp.h"
- #include "glyph-imp.h"
- #include "pixmap-imp.h"
- #include <ft2build.h>
- #include <assert.h>
- #include FT_FREETYPE_H
- #include FT_ADVANCES_H
- #include FT_MODULE_H
- #include FT_STROKER_H
- #include FT_SYSTEM_H
- #include FT_TRUETYPE_TABLES_H
- #include FT_TRUETYPE_TAGS_H
- #ifndef FT_SFNT_OS2
- #define FT_SFNT_OS2 ft_sfnt_os2
- #endif
- /* 20 degrees */
- #define SHEAR 0.36397f
- int ft_char_index(void *face, int cid)
- {
- int gid = FT_Get_Char_Index(face, cid);
- if (gid == 0)
- gid = FT_Get_Char_Index(face, 0xf000 + cid);
- /* some chinese fonts only ship the similarly looking 0x2026 */
- if (gid == 0 && cid == 0x22ef)
- gid = FT_Get_Char_Index(face, 0x2026);
- return gid;
- }
- int ft_name_index(void *face, const char *name)
- {
- int code = FT_Get_Name_Index(face, (char*)name);
- if (code == 0)
- {
- int unicode = fz_unicode_from_glyph_name(name);
- if (unicode)
- {
- const char **dupnames = fz_duplicate_glyph_names_from_unicode(unicode);
- while (*dupnames)
- {
- code = FT_Get_Name_Index(face, (char*)*dupnames);
- if (code)
- break;
- dupnames++;
- }
- if (code == 0)
- {
- char buf[12];
- sprintf(buf, "uni%04X", unicode);
- code = FT_Get_Name_Index(face, buf);
- }
- }
- }
- return code;
- }
- static void fz_drop_freetype(fz_context *ctx);
- static fz_font *
- fz_new_font(fz_context *ctx, const char *name, int use_glyph_bbox, int glyph_count)
- {
- fz_font *font;
- font = fz_malloc_struct(ctx, fz_font);
- font->refs = 1;
- if (name)
- fz_strlcpy(font->name, name, sizeof font->name);
- else
- fz_strlcpy(font->name, "(null)", sizeof font->name);
- font->ft_face = NULL;
- font->flags.ft_substitute = 0;
- font->flags.fake_bold = 0;
- font->flags.fake_italic = 0;
- font->flags.has_opentype = 0;
- font->flags.embed = 0;
- font->flags.never_embed = 0;
- font->t3matrix = fz_identity;
- font->t3resources = NULL;
- font->t3procs = NULL;
- font->t3lists = NULL;
- font->t3widths = NULL;
- font->t3flags = NULL;
- font->t3doc = NULL;
- font->t3run = NULL;
- font->bbox.x0 = 0;
- font->bbox.y0 = 0;
- font->bbox.x1 = 1;
- font->bbox.y1 = 1;
- font->glyph_count = glyph_count;
- font->bbox_table = NULL;
- font->use_glyph_bbox = use_glyph_bbox;
- font->width_count = 0;
- font->width_table = NULL;
- font->subfont = 0;
- return font;
- }
- fz_font *
- fz_keep_font(fz_context *ctx, fz_font *font)
- {
- return fz_keep_imp(ctx, font, &font->refs);
- }
- static void
- free_resources(fz_context *ctx, fz_font *font)
- {
- int i;
- if (font->t3resources)
- {
- font->t3freeres(ctx, font->t3doc, font->t3resources);
- font->t3resources = NULL;
- }
- if (font->t3procs)
- {
- for (i = 0; i < 256; i++)
- fz_drop_buffer(ctx, font->t3procs[i]);
- }
- fz_free(ctx, font->t3procs);
- font->t3procs = NULL;
- }
- /*
- Internal function to remove the
- references to a document held by a Type3 font. This is
- called during document destruction to ensure that Type3
- fonts clean up properly.
- Without this call being made, Type3 fonts can be left
- holding pdf_obj references for the sake of interpretation
- operations that will never come. These references
- cannot be freed after the document, hence this function
- forces them to be freed earlier in the process.
- font: The font to decouple.
- t3doc: The document to which the font may refer.
- */
- void fz_decouple_type3_font(fz_context *ctx, fz_font *font, void *t3doc)
- {
- if (!font || !t3doc || font->t3doc == NULL)
- return;
- if (font->t3doc != t3doc)
- fz_throw(ctx, FZ_ERROR_ARGUMENT, "can't decouple type3 font from a different doc");
- font->t3doc = NULL;
- free_resources(ctx, font);
- }
- void
- fz_drop_font(fz_context *ctx, fz_font *font)
- {
- int fterr;
- int i;
- if (!fz_drop_imp(ctx, font, &font->refs))
- return;
- free_resources(ctx, font);
- if (font->t3lists)
- for (i = 0; i < 256; i++)
- fz_drop_display_list(ctx, font->t3lists[i]);
- fz_free(ctx, font->t3procs);
- fz_free(ctx, font->t3lists);
- fz_free(ctx, font->t3widths);
- fz_free(ctx, font->t3flags);
- if (font->ft_face)
- {
- fz_ft_lock(ctx);
- fterr = FT_Done_Face((FT_Face)font->ft_face);
- fz_ft_unlock(ctx);
- if (fterr)
- fz_warn(ctx, "FT_Done_Face(%s): %s", font->name, ft_error_string(fterr));
- fz_drop_freetype(ctx);
- }
- for (i = 0; i < 256; ++i)
- fz_free(ctx, font->encoding_cache[i]);
- fz_drop_buffer(ctx, font->buffer);
- if (font->bbox_table)
- {
- int n = (font->glyph_count+255)/256;
- for (i = 0; i < n; i++)
- fz_free(ctx, font->bbox_table[i]);
- fz_free(ctx, font->bbox_table);
- }
- fz_free(ctx, font->width_table);
- if (font->advance_cache)
- {
- int n = (font->glyph_count+255)/256;
- for (i = 0; i < n; i++)
- fz_free(ctx, font->advance_cache[i]);
- fz_free(ctx, font->advance_cache);
- }
- if (font->shaper_data.destroy && font->shaper_data.shaper_handle)
- {
- font->shaper_data.destroy(ctx, font->shaper_data.shaper_handle);
- }
- fz_free(ctx, font);
- }
- void
- fz_set_font_bbox(fz_context *ctx, fz_font *font, float xmin, float ymin, float xmax, float ymax)
- {
- if (xmin >= xmax || ymin >= ymax)
- {
- /* Invalid bbox supplied. */
- if (font->t3procs)
- {
- /* For type3 fonts we use the union of all the glyphs' bboxes. */
- font->bbox = fz_empty_rect;
- }
- else
- {
- /* For other fonts it would be prohibitively slow to measure the true one, so make one up. */
- font->bbox = fz_unit_rect;
- }
- font->flags.invalid_bbox = 1;
- }
- else
- {
- font->bbox.x0 = xmin;
- font->bbox.y0 = ymin;
- font->bbox.x1 = xmax;
- font->bbox.y1 = ymax;
- }
- }
- float fz_font_ascender(fz_context *ctx, fz_font *font)
- {
- return font->ascender;
- }
- float fz_font_descender(fz_context *ctx, fz_font *font)
- {
- return font->descender;
- }
- /*
- * Freetype hooks
- */
- struct fz_font_context
- {
- int ctx_refs;
- FT_Library ftlib;
- struct FT_MemoryRec_ ftmemory;
- int ftlib_refs;
- fz_load_system_font_fn *load_font;
- fz_load_system_cjk_font_fn *load_cjk_font;
- fz_load_system_fallback_font_fn *load_fallback_font;
- /* Cached fallback fonts */
- fz_font *base14[14];
- fz_font *cjk[4];
- struct { fz_font *serif, *sans; } fallback[256];
- fz_font *symbol1, *symbol2, *math, *music, *boxes;
- fz_font *emoji;
- };
- #undef __FTERRORS_H__
- #define FT_ERRORDEF(e, v, s) { (e), (s) },
- #define FT_ERROR_START_LIST
- #define FT_ERROR_END_LIST { 0, NULL }
- struct ft_error
- {
- int err;
- char *str;
- };
- static void *ft_alloc(FT_Memory memory, long size)
- {
- fz_context *ctx = (fz_context *) memory->user;
- return Memento_label(fz_malloc_no_throw(ctx, size), "ft_alloc");
- }
- static void ft_free(FT_Memory memory, void *block)
- {
- fz_context *ctx = (fz_context *) memory->user;
- fz_free(ctx, block);
- }
- static void *ft_realloc(FT_Memory memory, long cur_size, long new_size, void *block)
- {
- fz_context *ctx = (fz_context *) memory->user;
- void *newblock = NULL;
- if (new_size == 0)
- {
- fz_free(ctx, block);
- return newblock;
- }
- if (block == NULL)
- return ft_alloc(memory, new_size);
- return fz_realloc_no_throw(ctx, block, new_size);
- }
- void
- fz_ft_lock(fz_context *ctx)
- {
- fz_lock(ctx, FZ_LOCK_FREETYPE);
- fz_lock(ctx, FZ_LOCK_ALLOC);
- assert(ctx->font->ftmemory.user == NULL);
- ctx->font->ftmemory.user = ctx;
- fz_unlock(ctx, FZ_LOCK_ALLOC);
- }
- void
- fz_ft_unlock(fz_context *ctx)
- {
- fz_lock(ctx, FZ_LOCK_ALLOC);
- ctx->font->ftmemory.user = NULL;
- fz_unlock(ctx, FZ_LOCK_ALLOC);
- fz_unlock(ctx, FZ_LOCK_FREETYPE);
- }
- int
- fz_ft_lock_held(fz_context *ctx)
- {
- /* If this thread has locked the freetype lock already, then
- * the stored context will be this one. */
- return (ctx->font->ftmemory.user == ctx);
- }
- void fz_new_font_context(fz_context *ctx)
- {
- ctx->font = fz_malloc_struct(ctx, fz_font_context);
- ctx->font->ctx_refs = 1;
- ctx->font->ftlib = NULL;
- ctx->font->ftlib_refs = 0;
- ctx->font->load_font = NULL;
- ctx->font->ftmemory.user = NULL;
- ctx->font->ftmemory.alloc = ft_alloc;
- ctx->font->ftmemory.free = ft_free;
- ctx->font->ftmemory.realloc = ft_realloc;
- }
- fz_font_context *
- fz_keep_font_context(fz_context *ctx)
- {
- if (!ctx)
- return NULL;
- return fz_keep_imp(ctx, ctx->font, &ctx->font->ctx_refs);
- }
- void fz_drop_font_context(fz_context *ctx)
- {
- if (!ctx)
- return;
- if (fz_drop_imp(ctx, ctx->font, &ctx->font->ctx_refs))
- {
- int i;
- for (i = 0; i < (int)nelem(ctx->font->base14); ++i)
- fz_drop_font(ctx, ctx->font->base14[i]);
- for (i = 0; i < (int)nelem(ctx->font->cjk); ++i)
- fz_drop_font(ctx, ctx->font->cjk[i]);
- for (i = 0; i < (int)nelem(ctx->font->fallback); ++i)
- {
- fz_drop_font(ctx, ctx->font->fallback[i].serif);
- fz_drop_font(ctx, ctx->font->fallback[i].sans);
- }
- fz_drop_font(ctx, ctx->font->symbol1);
- fz_drop_font(ctx, ctx->font->symbol2);
- fz_drop_font(ctx, ctx->font->math);
- fz_drop_font(ctx, ctx->font->music);
- fz_drop_font(ctx, ctx->font->emoji);
- fz_drop_font(ctx, ctx->font->boxes);
- fz_free(ctx, ctx->font);
- ctx->font = NULL;
- }
- }
- void fz_install_load_system_font_funcs(fz_context *ctx,
- fz_load_system_font_fn *f,
- fz_load_system_cjk_font_fn *f_cjk,
- fz_load_system_fallback_font_fn *f_back)
- {
- ctx->font->load_font = f;
- ctx->font->load_cjk_font = f_cjk;
- ctx->font->load_fallback_font = f_back;
- }
- /* fz_load_*_font returns NULL if no font could be loaded (also on error) */
- fz_font *fz_load_system_font(fz_context *ctx, const char *name, int bold, int italic, int needs_exact_metrics)
- {
- fz_font *font = NULL;
- if (ctx->font->load_font)
- {
- fz_try(ctx)
- font = ctx->font->load_font(ctx, name, bold, italic, needs_exact_metrics);
- fz_catch(ctx)
- {
- fz_rethrow_if(ctx, FZ_ERROR_TRYLATER);
- fz_rethrow_if(ctx, FZ_ERROR_SYSTEM);
- fz_report_error(ctx);
- font = NULL;
- }
- }
- return font;
- }
- fz_font *fz_load_system_cjk_font(fz_context *ctx, const char *name, int ros, int serif)
- {
- fz_font *font = NULL;
- if (ctx->font->load_cjk_font)
- {
- fz_try(ctx)
- font = ctx->font->load_cjk_font(ctx, name, ros, serif);
- fz_catch(ctx)
- {
- fz_rethrow_if(ctx, FZ_ERROR_TRYLATER);
- fz_rethrow_if(ctx, FZ_ERROR_SYSTEM);
- fz_report_error(ctx);
- font = NULL;
- }
- }
- return font;
- }
- fz_font *fz_load_system_fallback_font(fz_context *ctx, int script, int language, int serif, int bold, int italic)
- {
- fz_font *font = NULL;
- if (ctx->font->load_fallback_font)
- {
- fz_try(ctx)
- font = ctx->font->load_fallback_font(ctx, script, language, serif, bold, italic);
- fz_catch(ctx)
- {
- fz_rethrow_if(ctx, FZ_ERROR_TRYLATER);
- fz_rethrow_if(ctx, FZ_ERROR_SYSTEM);
- fz_report_error(ctx);
- font = NULL;
- }
- }
- return font;
- }
- fz_font *fz_load_fallback_font(fz_context *ctx, int script, int language, int serif, int bold, int italic)
- {
- fz_font **fontp;
- const unsigned char *data;
- int ordering = FZ_ADOBE_JAPAN;
- int index;
- int subfont;
- int size;
- if (script < 0 || script >= (int)nelem(ctx->font->fallback))
- return NULL;
- /* TODO: bold and italic */
- index = script;
- if (script == UCDN_SCRIPT_HAN)
- {
- switch (language)
- {
- case FZ_LANG_ja: index = UCDN_LAST_SCRIPT + 1; ordering = FZ_ADOBE_JAPAN; break;
- case FZ_LANG_ko: index = UCDN_LAST_SCRIPT + 2; ordering = FZ_ADOBE_KOREA; break;
- case FZ_LANG_zh_Hans: index = UCDN_LAST_SCRIPT + 3; ordering = FZ_ADOBE_GB; break;
- case FZ_LANG_zh_Hant: index = UCDN_LAST_SCRIPT + 4; ordering = FZ_ADOBE_CNS; break;
- }
- }
- if (script == UCDN_SCRIPT_ARABIC)
- {
- if (language == FZ_LANG_ur || language == FZ_LANG_urd)
- index = UCDN_LAST_SCRIPT + 5;
- }
- if (serif)
- fontp = &ctx->font->fallback[index].serif;
- else
- fontp = &ctx->font->fallback[index].sans;
- if (!*fontp)
- {
- *fontp = fz_load_system_fallback_font(ctx, script, language, serif, bold, italic);
- if (!*fontp)
- {
- data = fz_lookup_noto_font(ctx, script, language, &size, &subfont);
- if (data)
- {
- *fontp = fz_new_font_from_memory(ctx, NULL, data, size, subfont, 0);
- /* Noto fonts can be embedded. */
- fz_set_font_embedding(ctx, *fontp, 1);
- }
- }
- }
- switch (script)
- {
- case UCDN_SCRIPT_HANGUL: script = UCDN_SCRIPT_HAN; ordering = FZ_ADOBE_KOREA; break;
- case UCDN_SCRIPT_HIRAGANA: script = UCDN_SCRIPT_HAN; ordering = FZ_ADOBE_JAPAN; break;
- case UCDN_SCRIPT_KATAKANA: script = UCDN_SCRIPT_HAN; ordering = FZ_ADOBE_JAPAN; break;
- case UCDN_SCRIPT_BOPOMOFO: script = UCDN_SCRIPT_HAN; ordering = FZ_ADOBE_CNS; break;
- }
- if (*fontp && (script == UCDN_SCRIPT_HAN))
- {
- (*fontp)->flags.cjk = 1;
- (*fontp)->flags.cjk_lang = ordering;
- }
- return *fontp;
- }
- static fz_font *fz_load_fallback_math_font(fz_context *ctx)
- {
- const unsigned char *data;
- int size;
- if (!ctx->font->math)
- {
- data = fz_lookup_noto_math_font(ctx, &size);
- if (data)
- ctx->font->math = fz_new_font_from_memory(ctx, NULL, data, size, 0, 0);
- }
- return ctx->font->math;
- }
- static fz_font *fz_load_fallback_music_font(fz_context *ctx)
- {
- const unsigned char *data;
- int size;
- if (!ctx->font->music)
- {
- data = fz_lookup_noto_music_font(ctx, &size);
- if (data)
- ctx->font->music = fz_new_font_from_memory(ctx, NULL, data, size, 0, 0);
- }
- return ctx->font->music;
- }
- static fz_font *fz_load_fallback_symbol1_font(fz_context *ctx)
- {
- const unsigned char *data;
- int size;
- if (!ctx->font->symbol1)
- {
- data = fz_lookup_noto_symbol1_font(ctx, &size);
- if (data)
- ctx->font->symbol1 = fz_new_font_from_memory(ctx, NULL, data, size, 0, 0);
- }
- return ctx->font->symbol1;
- }
- static fz_font *fz_load_fallback_symbol2_font(fz_context *ctx)
- {
- const unsigned char *data;
- int size;
- if (!ctx->font->symbol2)
- {
- data = fz_lookup_noto_symbol2_font(ctx, &size);
- if (data)
- ctx->font->symbol2 = fz_new_font_from_memory(ctx, NULL, data, size, 0, 0);
- }
- return ctx->font->symbol2;
- }
- static fz_font *fz_load_fallback_emoji_font(fz_context *ctx)
- {
- const unsigned char *data;
- int size;
- if (!ctx->font->emoji)
- {
- data = fz_lookup_noto_emoji_font(ctx, &size);
- if (data)
- ctx->font->emoji = fz_new_font_from_memory(ctx, NULL, data, size, 0, 0);
- }
- return ctx->font->emoji;
- }
- static fz_font *fz_load_fallback_boxes_font(fz_context *ctx)
- {
- const unsigned char *data;
- int size;
- if (!ctx->font->boxes)
- {
- data = fz_lookup_noto_boxes_font(ctx, &size);
- if (data)
- ctx->font->boxes = fz_new_font_from_memory(ctx, NULL, data, size, 0, 0);
- }
- return ctx->font->boxes;
- }
- static const struct ft_error ft_errors[] =
- {
- #include FT_ERRORS_H
- };
- const char *ft_error_string(int err)
- {
- const struct ft_error *e;
- for (e = ft_errors; e->str; e++)
- if (e->err == err)
- return e->str;
- return "Unknown error";
- }
- static void
- fz_keep_freetype(fz_context *ctx)
- {
- int fterr;
- int maj, min, pat;
- fz_font_context *fct = ctx->font;
- fz_ft_lock(ctx);
- if (fct->ftlib)
- {
- fct->ftlib_refs++;
- fz_ft_unlock(ctx);
- return;
- }
- fterr = FT_New_Library(&fct->ftmemory, &fct->ftlib);
- if (fterr)
- {
- const char *mess = ft_error_string(fterr);
- fz_ft_unlock(ctx);
- fz_throw(ctx, FZ_ERROR_LIBRARY, "cannot init freetype: %s", mess);
- }
- FT_Add_Default_Modules(fct->ftlib);
- FT_Library_Version(fct->ftlib, &maj, &min, &pat);
- if (maj == 2 && min == 1 && pat < 7)
- {
- fterr = FT_Done_Library(fct->ftlib);
- if (fterr)
- fz_warn(ctx, "FT_Done_Library(): %s", ft_error_string(fterr));
- fz_ft_unlock(ctx);
- fz_throw(ctx, FZ_ERROR_LIBRARY, "freetype version too old: %d.%d.%d", maj, min, pat);
- }
- fct->ftlib_refs++;
- fz_ft_unlock(ctx);
- }
- static void
- fz_drop_freetype(fz_context *ctx)
- {
- int fterr;
- fz_font_context *fct = ctx->font;
- fz_ft_lock(ctx);
- if (--fct->ftlib_refs == 0)
- {
- fterr = FT_Done_Library(fct->ftlib);
- if (fterr)
- fz_warn(ctx, "FT_Done_Library(): %s", ft_error_string(fterr));
- fct->ftlib = NULL;
- }
- fz_ft_unlock(ctx);
- }
- fz_font *
- fz_new_font_from_buffer(fz_context *ctx, const char *name, fz_buffer *buffer, int index, int use_glyph_bbox)
- {
- FT_Face face;
- TT_OS2 *os2;
- fz_font *font;
- int fterr;
- FT_ULong tag, size, i, n;
- FT_UShort flags;
- char namebuf[sizeof(font->name)];
- fz_ascdesc_source ascdesc_src = FZ_ASCDESC_FROM_FONT;
- fz_keep_freetype(ctx);
- fz_ft_lock(ctx);
- fterr = FT_New_Memory_Face(ctx->font->ftlib, buffer->data, (FT_Long)buffer->len, index, &face);
- fz_ft_unlock(ctx);
- if (fterr)
- {
- fz_drop_freetype(ctx);
- fz_throw(ctx, FZ_ERROR_LIBRARY, "FT_New_Memory_Face(%s): %s", name, ft_error_string(fterr));
- }
- if (!name)
- {
- if (!face->family_name)
- {
- name = face->style_name;
- }
- else if (!face->style_name)
- {
- name = face->family_name;
- }
- else if (strstr(face->style_name, face->family_name) == face->style_name)
- {
- name = face->style_name;
- }
- else
- {
- fz_strlcpy(namebuf, face->family_name, sizeof(namebuf));
- fz_strlcat(namebuf, " ", sizeof(namebuf));
- fz_strlcat(namebuf, face->style_name, sizeof(namebuf));
- name = namebuf;
- }
- }
- fz_try(ctx)
- font = fz_new_font(ctx, name, use_glyph_bbox, face->num_glyphs);
- fz_catch(ctx)
- {
- fz_ft_lock(ctx);
- fterr = FT_Done_Face(face);
- fz_ft_unlock(ctx);
- if (fterr)
- fz_warn(ctx, "FT_Done_Face(%s): %s", name, ft_error_string(fterr));
- fz_drop_freetype(ctx);
- fz_rethrow(ctx);
- }
- font->ft_face = face;
- fz_set_font_bbox(ctx, font,
- (float) face->bbox.xMin / face->units_per_EM,
- (float) face->bbox.yMin / face->units_per_EM,
- (float) face->bbox.xMax / face->units_per_EM,
- (float) face->bbox.yMax / face->units_per_EM);
- if (face->ascender <= 0 || face->ascender > FZ_MAX_TRUSTWORTHY_ASCENT * face->units_per_EM)
- font->ascender = 0.8f, ascdesc_src = FZ_ASCDESC_DEFAULT;
- else
- font->ascender = (float)face->ascender / face->units_per_EM;
- if (face->descender < FZ_MAX_TRUSTWORTHY_DESCENT * face->units_per_EM || face->descender > -FZ_MAX_TRUSTWORTHY_DESCENT * face->units_per_EM)
- font->descender = -0.2f, ascdesc_src = FZ_ASCDESC_DEFAULT;
- else
- {
- font->descender = (float)face->descender / face->units_per_EM;
- if (font->descender > 0)
- font->descender = -font->descender;
- }
- font->ascdesc_src = ascdesc_src;
- font->subfont = index;
- font->flags.is_mono = !!(face->face_flags & FT_FACE_FLAG_FIXED_WIDTH);
- font->flags.is_serif = 1;
- font->flags.is_bold = !!(face->style_flags & FT_STYLE_FLAG_BOLD);
- font->flags.is_italic = !!(face->style_flags & FT_STYLE_FLAG_ITALIC);
- font->flags.embed = 1;
- font->flags.never_embed = 0;
- if (FT_IS_SFNT(face))
- {
- fz_ft_lock(ctx);
- os2 = FT_Get_Sfnt_Table(face, FT_SFNT_OS2);
- if (os2)
- font->flags.is_serif = !(os2->sFamilyClass & 2048); /* Class 8 is sans-serif */
- flags = FT_Get_FSType_Flags(face);
- if (flags & (FT_FSTYPE_RESTRICTED_LICENSE_EMBEDDING |
- FT_FSTYPE_BITMAP_EMBEDDING_ONLY))
- {
- font->flags.never_embed = 1;
- font->flags.embed = 0;
- }
- FT_Sfnt_Table_Info(face, 0, NULL, &n);
- for (i = 0; i < n; ++i)
- {
- FT_Sfnt_Table_Info(face, i, &tag, &size);
- if (tag == TTAG_GDEF || tag == TTAG_GPOS || tag == TTAG_GSUB)
- font->flags.has_opentype = 1;
- }
- fz_ft_unlock(ctx);
- }
- if (name)
- {
- if (!font->flags.is_bold)
- {
- if (strstr(name, "Semibold")) font->flags.is_bold = 1;
- if (strstr(name, "Bold")) font->flags.is_bold = 1;
- }
- if (!font->flags.is_italic)
- {
- if (strstr(name, "Italic")) font->flags.is_italic = 1;
- if (strstr(name, "Oblique")) font->flags.is_italic = 1;
- }
- }
- font->buffer = fz_keep_buffer(ctx, buffer);
- return font;
- }
- fz_font *
- fz_new_font_from_memory(fz_context *ctx, const char *name, const unsigned char *data, int len, int index, int use_glyph_bbox)
- {
- fz_buffer *buffer = fz_new_buffer_from_shared_data(ctx, data, len);
- fz_font *font = NULL;
- fz_try(ctx)
- font = fz_new_font_from_buffer(ctx, name, buffer, index, use_glyph_bbox);
- fz_always(ctx)
- fz_drop_buffer(ctx, buffer);
- fz_catch(ctx)
- fz_rethrow(ctx);
- return font;
- }
- fz_font *
- fz_new_font_from_file(fz_context *ctx, const char *name, const char *path, int index, int use_glyph_bbox)
- {
- fz_buffer *buffer = fz_read_file(ctx, path);
- fz_font *font = NULL;
- fz_try(ctx)
- font = fz_new_font_from_buffer(ctx, name, buffer, index, use_glyph_bbox);
- fz_always(ctx)
- fz_drop_buffer(ctx, buffer);
- fz_catch(ctx)
- fz_rethrow(ctx);
- return font;
- }
- void fz_set_font_embedding(fz_context *ctx, fz_font *font, int embed)
- {
- if (!font)
- return;
- if (embed)
- {
- if (font->flags.never_embed)
- fz_warn(ctx, "not allowed to embed font: %s", font->name);
- else
- font->flags.embed = 1;
- }
- else
- {
- font->flags.embed = 0;
- }
- }
- static int
- find_base14_index(const char *name)
- {
- if (!strcmp(name, "Courier")) return 0;
- if (!strcmp(name, "Courier-Oblique")) return 1;
- if (!strcmp(name, "Courier-Bold")) return 2;
- if (!strcmp(name, "Courier-BoldOblique")) return 3;
- if (!strcmp(name, "Helvetica")) return 4;
- if (!strcmp(name, "Helvetica-Oblique")) return 5;
- if (!strcmp(name, "Helvetica-Bold")) return 6;
- if (!strcmp(name, "Helvetica-BoldOblique")) return 7;
- if (!strcmp(name, "Times-Roman")) return 8;
- if (!strcmp(name, "Times-Italic")) return 9;
- if (!strcmp(name, "Times-Bold")) return 10;
- if (!strcmp(name, "Times-BoldItalic")) return 11;
- if (!strcmp(name, "Symbol")) return 12;
- if (!strcmp(name, "ZapfDingbats")) return 13;
- return -1;
- }
- fz_font *
- fz_new_base14_font(fz_context *ctx, const char *name)
- {
- const unsigned char *data;
- int size;
- int x = find_base14_index(name);
- if (x >= 0)
- {
- if (ctx->font->base14[x])
- return fz_keep_font(ctx, ctx->font->base14[x]);
- data = fz_lookup_base14_font(ctx, name, &size);
- if (data)
- {
- ctx->font->base14[x] = fz_new_font_from_memory(ctx, name, data, size, 0, 1);
- ctx->font->base14[x]->flags.is_serif = (name[0] == 'T'); /* Times-Roman */
- /* Ideally we should not embed base14 fonts by default, but we have to
- * allow it for now until we have written code in pdf-device to output
- * base14s in a 'special' manner. */
- fz_set_font_embedding(ctx, ctx->font->base14[x], 1);
- return fz_keep_font(ctx, ctx->font->base14[x]);
- }
- }
- fz_throw(ctx, FZ_ERROR_ARGUMENT, "cannot find builtin font with name '%s'", name);
- }
- fz_font *
- fz_new_cjk_font(fz_context *ctx, int ordering)
- {
- const unsigned char *data;
- int size, index;
- fz_font *font;
- if (ordering >= 0 && ordering < (int)nelem(ctx->font->cjk))
- {
- if (ctx->font->cjk[ordering])
- return fz_keep_font(ctx, ctx->font->cjk[ordering]);
- data = fz_lookup_cjk_font(ctx, ordering, &size, &index);
- if (data)
- font = fz_new_font_from_memory(ctx, NULL, data, size, index, 0);
- else
- font = fz_load_system_cjk_font(ctx, "SourceHanSerif", ordering, 1);
- /* FIXME: Currently the builtin one at least will be set to embed. Is that right? */
- if (font)
- {
- font->flags.cjk = 1;
- font->flags.cjk_lang = ordering;
- ctx->font->cjk[ordering] = font;
- return fz_keep_font(ctx, ctx->font->cjk[ordering]);
- }
- }
- fz_throw(ctx, FZ_ERROR_ARGUMENT, "cannot find builtin CJK font");
- }
- fz_font *
- fz_new_builtin_font(fz_context *ctx, const char *name, int is_bold, int is_italic)
- {
- const unsigned char *data;
- int size;
- fz_font *font;
- data = fz_lookup_builtin_font(ctx, name, is_bold, is_italic, &size);
- if (!data)
- fz_throw(ctx, FZ_ERROR_ARGUMENT, "cannot find builtin font with name '%s'", name);
- font = fz_new_font_from_memory(ctx, NULL, data, size, 0, 0);
- /* Don't embed builtin fonts. */
- fz_set_font_embedding(ctx, font, 0);
- return font;
- }
- static fz_matrix *
- fz_adjust_ft_glyph_width(fz_context *ctx, fz_font *font, int gid, fz_matrix *trm)
- {
- /* Fudge the font matrix to stretch the glyph if we've substituted the font. */
- if (font->flags.ft_stretch && font->width_table /* && font->wmode == 0 */)
- {
- FT_Error fterr;
- FT_Fixed adv = 0;
- float subw;
- float realw;
- fz_ft_lock(ctx);
- fterr = FT_Get_Advance(font->ft_face, gid, FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING | FT_LOAD_IGNORE_TRANSFORM, &adv);
- fz_ft_unlock(ctx);
- if (fterr && fterr != FT_Err_Invalid_Argument)
- fz_warn(ctx, "FT_Get_Advance(%s,%d): %s", font->name, gid, ft_error_string(fterr));
- realw = adv * 1000.0f / ((FT_Face)font->ft_face)->units_per_EM;
- if (gid < font->width_count)
- subw = font->width_table[gid];
- else
- subw = font->width_default;
- /* Sanity check scaling in case of broken metrics. */
- if (realw > 0 && subw > 0)
- *trm = fz_pre_scale(*trm, subw / realw, 1);
- }
- return trm;
- }
- static fz_glyph *
- glyph_from_ft_bitmap(fz_context *ctx, int left, int top, FT_Bitmap *bitmap)
- {
- (void)Memento_label(bitmap->buffer, "ft_bitmap");
- if (bitmap->pixel_mode == FT_PIXEL_MODE_MONO)
- return fz_new_glyph_from_1bpp_data(ctx, left, top - bitmap->rows, bitmap->width, bitmap->rows, bitmap->buffer + (bitmap->rows-1)*bitmap->pitch, -bitmap->pitch);
- else
- return fz_new_glyph_from_8bpp_data(ctx, left, top - bitmap->rows, bitmap->width, bitmap->rows, bitmap->buffer + (bitmap->rows-1)*bitmap->pitch, -bitmap->pitch);
- }
- static fz_pixmap *
- pixmap_from_ft_bitmap(fz_context *ctx, int left, int top, FT_Bitmap *bitmap)
- {
- (void)Memento_label(bitmap->buffer, "ft_bitmap");
- if (bitmap->pixel_mode == FT_PIXEL_MODE_MONO)
- return fz_new_pixmap_from_1bpp_data(ctx, left, top - bitmap->rows, bitmap->width, bitmap->rows, bitmap->buffer + (bitmap->rows-1)*bitmap->pitch, -bitmap->pitch);
- else
- return fz_new_pixmap_from_8bpp_data(ctx, left, top - bitmap->rows, bitmap->width, bitmap->rows, bitmap->buffer + (bitmap->rows-1)*bitmap->pitch, -bitmap->pitch);
- }
- /* Takes the freetype lock, and returns with it held */
- static FT_GlyphSlot
- do_ft_render_glyph(fz_context *ctx, fz_font *font, int gid, fz_matrix trm, int aa)
- {
- FT_Face face = font->ft_face;
- FT_Matrix m;
- FT_Vector v;
- FT_Error fterr;
- float strength = fz_matrix_expansion(trm) * 0.02f;
- fz_adjust_ft_glyph_width(ctx, font, gid, &trm);
- if (font->flags.fake_italic)
- trm = fz_pre_shear(trm, SHEAR, 0);
- fz_ft_lock(ctx);
- if (aa == 0)
- {
- /* enable grid fitting for non-antialiased rendering */
- float scale = fz_matrix_expansion(trm);
- m.xx = trm.a * 65536 / scale;
- m.yx = trm.b * 65536 / scale;
- m.xy = trm.c * 65536 / scale;
- m.yy = trm.d * 65536 / scale;
- v.x = 0;
- v.y = 0;
- fterr = FT_Set_Char_Size(face, 64 * scale, 64 * scale, 72, 72);
- if (fterr)
- fz_warn(ctx, "FT_Set_Char_Size(%s,%d,72): %s", font->name, (int)(64*scale), ft_error_string(fterr));
- FT_Set_Transform(face, &m, &v);
- fterr = FT_Load_Glyph(face, gid, FT_LOAD_NO_BITMAP | FT_LOAD_TARGET_MONO);
- if (fterr)
- {
- fz_warn(ctx, "FT_Load_Glyph(%s,%d,FT_LOAD_TARGET_MONO): %s", font->name, gid, ft_error_string(fterr));
- goto retry_unhinted;
- }
- }
- else
- {
- retry_unhinted:
- /*
- * Freetype mutilates complex glyphs if they are loaded with
- * FT_Set_Char_Size 1.0. It rounds the coordinates before applying
- * transformation. To get more precision in freetype, we shift part of
- * the scale in the matrix into FT_Set_Char_Size instead.
- */
- /* Check for overflow; FreeType matrices use 16.16 fixed-point numbers */
- if (trm.a < -512 || trm.a > 512) return NULL;
- if (trm.b < -512 || trm.b > 512) return NULL;
- if (trm.c < -512 || trm.c > 512) return NULL;
- if (trm.d < -512 || trm.d > 512) return NULL;
- m.xx = trm.a * 64; /* should be 65536 */
- m.yx = trm.b * 64;
- m.xy = trm.c * 64;
- m.yy = trm.d * 64;
- v.x = trm.e * 64;
- v.y = trm.f * 64;
- fterr = FT_Set_Char_Size(face, 65536, 65536, 72, 72); /* should be 64, 64 */
- if (fterr)
- fz_warn(ctx, "FT_Set_Char_Size(%s,65536,72): %s", font->name, ft_error_string(fterr));
- FT_Set_Transform(face, &m, &v);
- fterr = FT_Load_Glyph(face, gid, FT_LOAD_NO_BITMAP | FT_LOAD_NO_HINTING);
- if (fterr)
- {
- fz_warn(ctx, "FT_Load_Glyph(%s,%d,FT_LOAD_NO_HINTING): %s", font->name, gid, ft_error_string(fterr));
- return NULL;
- }
- }
- if (font->flags.fake_bold)
- {
- FT_Outline_Embolden(&face->glyph->outline, strength * 64);
- FT_Outline_Translate(&face->glyph->outline, -strength * 32, -strength * 32);
- }
- fterr = FT_Render_Glyph(face->glyph, aa > 0 ? FT_RENDER_MODE_NORMAL : FT_RENDER_MODE_MONO);
- if (fterr)
- {
- if (aa > 0)
- fz_warn(ctx, "FT_Render_Glyph(%s,%d,FT_RENDER_MODE_NORMAL): %s", font->name, gid, ft_error_string(fterr));
- else
- fz_warn(ctx, "FT_Render_Glyph(%s,%d,FT_RENDER_MODE_MONO): %s", font->name, gid, ft_error_string(fterr));
- return NULL;
- }
- return face->glyph;
- }
- fz_pixmap *
- fz_render_ft_glyph_pixmap(fz_context *ctx, fz_font *font, int gid, fz_matrix trm, int aa)
- {
- FT_GlyphSlot slot = do_ft_render_glyph(ctx, font, gid, trm, aa);
- fz_pixmap *pixmap = NULL;
- if (slot == NULL)
- {
- fz_ft_unlock(ctx);
- return NULL;
- }
- fz_try(ctx)
- {
- pixmap = pixmap_from_ft_bitmap(ctx, slot->bitmap_left, slot->bitmap_top, &slot->bitmap);
- }
- fz_always(ctx)
- {
- fz_ft_unlock(ctx);
- }
- fz_catch(ctx)
- {
- fz_rethrow(ctx);
- }
- return pixmap;
- }
- /* The glyph cache lock is always taken when this is called. */
- fz_glyph *
- fz_render_ft_glyph(fz_context *ctx, fz_font *font, int gid, fz_matrix trm, int aa)
- {
- FT_GlyphSlot slot = do_ft_render_glyph(ctx, font, gid, trm, aa);
- fz_glyph *glyph = NULL;
- if (slot == NULL)
- {
- fz_ft_unlock(ctx);
- return NULL;
- }
- fz_try(ctx)
- {
- glyph = glyph_from_ft_bitmap(ctx, slot->bitmap_left, slot->bitmap_top, &slot->bitmap);
- }
- fz_always(ctx)
- {
- fz_ft_unlock(ctx);
- }
- fz_catch(ctx)
- {
- fz_rethrow(ctx);
- }
- return glyph;
- }
- /* Takes the freetype lock, and returns with it held */
- static FT_Glyph
- do_render_ft_stroked_glyph(fz_context *ctx, fz_font *font, int gid, fz_matrix trm, fz_matrix ctm, const fz_stroke_state *state, int aa)
- {
- FT_Face face = font->ft_face;
- float expansion = fz_matrix_expansion(ctm);
- int linewidth = state->linewidth * expansion * 64 / 2;
- FT_Matrix m;
- FT_Vector v;
- FT_Error fterr;
- FT_Stroker stroker;
- FT_Glyph glyph;
- FT_Stroker_LineJoin line_join;
- FT_Stroker_LineCap line_cap;
- fz_adjust_ft_glyph_width(ctx, font, gid, &trm);
- if (font->flags.fake_italic)
- trm = fz_pre_shear(trm, SHEAR, 0);
- m.xx = trm.a * 64; /* should be 65536 */
- m.yx = trm.b * 64;
- m.xy = trm.c * 64;
- m.yy = trm.d * 64;
- v.x = trm.e * 64;
- v.y = trm.f * 64;
- fz_ft_lock(ctx);
- fterr = FT_Set_Char_Size(face, 65536, 65536, 72, 72); /* should be 64, 64 */
- if (fterr)
- {
- fz_warn(ctx, "FT_Set_Char_Size(%s,65536,72): %s", font->name, ft_error_string(fterr));
- return NULL;
- }
- FT_Set_Transform(face, &m, &v);
- fterr = FT_Load_Glyph(face, gid, FT_LOAD_NO_BITMAP | FT_LOAD_NO_HINTING);
- if (fterr)
- {
- fz_warn(ctx, "FT_Load_Glyph(%s,%d,FT_LOAD_NO_HINTING): %s", font->name, gid, ft_error_string(fterr));
- return NULL;
- }
- fterr = FT_Stroker_New(ctx->font->ftlib, &stroker);
- if (fterr)
- {
- fz_warn(ctx, "FT_Stroker_New(): %s", ft_error_string(fterr));
- return NULL;
- }
- line_join =
- state->linejoin == FZ_LINEJOIN_MITER ? FT_STROKER_LINEJOIN_MITER_FIXED :
- state->linejoin == FZ_LINEJOIN_ROUND ? FT_STROKER_LINEJOIN_ROUND :
- state->linejoin == FZ_LINEJOIN_BEVEL ? FT_STROKER_LINEJOIN_BEVEL :
- FT_STROKER_LINEJOIN_MITER_VARIABLE;
- line_cap =
- state->start_cap == FZ_LINECAP_BUTT ? FT_STROKER_LINECAP_BUTT :
- state->start_cap == FZ_LINECAP_ROUND ? FT_STROKER_LINECAP_ROUND :
- state->start_cap == FZ_LINECAP_SQUARE ? FT_STROKER_LINECAP_SQUARE :
- state->start_cap == FZ_LINECAP_TRIANGLE ? FT_STROKER_LINECAP_BUTT :
- FT_STROKER_LINECAP_BUTT;
- FT_Stroker_Set(stroker, linewidth, line_cap, line_join, state->miterlimit * 65536);
- fterr = FT_Get_Glyph(face->glyph, &glyph);
- if (fterr)
- {
- fz_warn(ctx, "FT_Get_Glyph(): %s", ft_error_string(fterr));
- FT_Stroker_Done(stroker);
- return NULL;
- }
- fterr = FT_Glyph_Stroke(&glyph, stroker, 1);
- if (fterr)
- {
- fz_warn(ctx, "FT_Glyph_Stroke(): %s", ft_error_string(fterr));
- FT_Done_Glyph(glyph);
- FT_Stroker_Done(stroker);
- return NULL;
- }
- FT_Stroker_Done(stroker);
- fterr = FT_Glyph_To_Bitmap(&glyph, aa > 0 ? FT_RENDER_MODE_NORMAL : FT_RENDER_MODE_MONO, 0, 1);
- if (fterr)
- {
- fz_warn(ctx, "FT_Glyph_To_Bitmap(): %s", ft_error_string(fterr));
- FT_Done_Glyph(glyph);
- return NULL;
- }
- return glyph;
- }
- fz_glyph *
- fz_render_ft_stroked_glyph(fz_context *ctx, fz_font *font, int gid, fz_matrix trm, fz_matrix ctm, const fz_stroke_state *state, int aa)
- {
- FT_Glyph glyph = do_render_ft_stroked_glyph(ctx, font, gid, trm, ctm, state, aa);
- FT_BitmapGlyph bitmap = (FT_BitmapGlyph)glyph;
- fz_glyph *result = NULL;
- if (bitmap == NULL)
- {
- fz_ft_unlock(ctx);
- return NULL;
- }
- fz_try(ctx)
- {
- result = glyph_from_ft_bitmap(ctx, bitmap->left, bitmap->top, &bitmap->bitmap);
- }
- fz_always(ctx)
- {
- FT_Done_Glyph(glyph);
- fz_ft_unlock(ctx);
- }
- fz_catch(ctx)
- {
- fz_rethrow(ctx);
- }
- return result;
- }
- static fz_rect *
- get_gid_bbox(fz_context *ctx, fz_font *font, int gid)
- {
- int i;
- if (gid < 0 || gid >= font->glyph_count || !font->use_glyph_bbox)
- return NULL;
- if (font->bbox_table == NULL) {
- i = (font->glyph_count + 255)/256;
- font->bbox_table = Memento_label(fz_malloc_array(ctx, i, fz_rect *), "bbox_table(top)");
- memset(font->bbox_table, 0, sizeof(fz_rect *) * i);
- }
- if (font->bbox_table[gid>>8] == NULL) {
- font->bbox_table[gid>>8] = Memento_label(fz_malloc_array(ctx, 256, fz_rect), "bbox_table");
- for (i = 0; i < 256; i++) {
- font->bbox_table[gid>>8][i] = fz_empty_rect;
- }
- }
- return &font->bbox_table[gid>>8][gid & 255];
- }
- static fz_rect *
- fz_bound_ft_glyph(fz_context *ctx, fz_font *font, int gid)
- {
- FT_Face face = font->ft_face;
- FT_Error fterr;
- FT_BBox cbox;
- FT_Matrix m;
- FT_Vector v;
- fz_rect *bounds = get_gid_bbox(ctx, font, gid);
- // TODO: refactor loading into fz_load_ft_glyph
- // TODO: cache results
- const int scale = face->units_per_EM;
- const float recip = 1.0f / scale;
- const float strength = 0.02f;
- fz_matrix trm = fz_identity;
- fz_adjust_ft_glyph_width(ctx, font, gid, &trm);
- if (font->flags.fake_italic)
- trm = fz_pre_shear(trm, SHEAR, 0);
- m.xx = trm.a * 65536;
- m.yx = trm.b * 65536;
- m.xy = trm.c * 65536;
- m.yy = trm.d * 65536;
- v.x = trm.e * 65536;
- v.y = trm.f * 65536;
- fz_ft_lock(ctx);
- /* Set the char size to scale=face->units_per_EM to effectively give
- * us unscaled results. This avoids quantisation. We then apply the
- * scale ourselves below. */
- fterr = FT_Set_Char_Size(face, scale, scale, 72, 72);
- if (fterr)
- fz_warn(ctx, "FT_Set_Char_Size(%s,%d,72): %s", font->name, scale, ft_error_string(fterr));
- FT_Set_Transform(face, &m, &v);
- fterr = FT_Load_Glyph(face, gid, FT_LOAD_NO_BITMAP | FT_LOAD_NO_HINTING);
- if (fterr)
- {
- fz_warn(ctx, "FT_Load_Glyph(%s,%d,FT_LOAD_NO_HINTING): %s", font->name, gid, ft_error_string(fterr));
- fz_ft_unlock(ctx);
- bounds->x0 = bounds->x1 = trm.e;
- bounds->y0 = bounds->y1 = trm.f;
- return bounds;
- }
- if (font->flags.fake_bold)
- {
- FT_Outline_Embolden(&face->glyph->outline, strength * scale);
- FT_Outline_Translate(&face->glyph->outline, -strength * 0.5f * scale, -strength * 0.5f * scale);
- }
- FT_Outline_Get_CBox(&face->glyph->outline, &cbox);
- fz_ft_unlock(ctx);
- bounds->x0 = cbox.xMin * recip;
- bounds->y0 = cbox.yMin * recip;
- bounds->x1 = cbox.xMax * recip;
- bounds->y1 = cbox.yMax * recip;
- if (fz_is_empty_rect(*bounds))
- {
- bounds->x0 = bounds->x1 = trm.e;
- bounds->y0 = bounds->y1 = trm.f;
- }
- return bounds;
- }
- /* Turn FT_Outline into a fz_path */
- struct closure {
- fz_context *ctx;
- fz_path *path;
- fz_matrix trm;
- };
- static int move_to(const FT_Vector *p, void *cc_)
- {
- struct closure *cc = (struct closure *)cc_;
- fz_context *ctx = cc->ctx;
- fz_path *path = cc->path;
- fz_point pt;
- pt = fz_transform_point_xy(p->x, p->y, cc->trm);
- fz_moveto(ctx, path, pt.x, pt.y);
- return 0;
- }
- static int line_to(const FT_Vector *p, void *cc_)
- {
- struct closure *cc = (struct closure *)cc_;
- fz_context *ctx = cc->ctx;
- fz_path *path = cc->path;
- fz_point pt;
- pt = fz_transform_point_xy(p->x, p->y, cc->trm);
- fz_lineto(ctx, path, pt.x, pt.y);
- return 0;
- }
- static int conic_to(const FT_Vector *c, const FT_Vector *p, void *cc_)
- {
- struct closure *cc = (struct closure *)cc_;
- fz_context *ctx = cc->ctx;
- fz_path *path = cc->path;
- fz_point ct, pt;
- ct = fz_transform_point_xy(c->x, c->y, cc->trm);
- pt = fz_transform_point_xy(p->x, p->y, cc->trm);
- fz_quadto(ctx, path, ct.x, ct.y, pt.x, pt.y);
- return 0;
- }
- static int cubic_to(const FT_Vector *c1, const FT_Vector *c2, const FT_Vector *p, void *cc_)
- {
- struct closure *cc = (struct closure *)cc_;
- fz_context *ctx = cc->ctx;
- fz_path *path = cc->path;
- fz_point c1t, c2t, pt;
- c1t = fz_transform_point_xy(c1->x, c1->y, cc->trm);
- c2t = fz_transform_point_xy(c2->x, c2->y, cc->trm);
- pt = fz_transform_point_xy(p->x, p->y, cc->trm);
- fz_curveto(ctx, path, c1t.x, c1t.y, c2t.x, c2t.y, pt.x, pt.y);
- return 0;
- }
- static const FT_Outline_Funcs outline_funcs = {
- move_to, line_to, conic_to, cubic_to, 0, 0
- };
- fz_path *
- fz_outline_ft_glyph(fz_context *ctx, fz_font *font, int gid, fz_matrix trm)
- {
- struct closure cc;
- FT_Face face = font->ft_face;
- int fterr;
- const int scale = 65536;
- const float recip = 1.0f / scale;
- const float strength = 0.02f;
- fz_adjust_ft_glyph_width(ctx, font, gid, &trm);
- if (font->flags.fake_italic)
- trm = fz_pre_shear(trm, SHEAR, 0);
- fz_ft_lock(ctx);
- fterr = FT_Set_Char_Size(face, scale, scale, 72, 72);
- if (fterr)
- fz_warn(ctx, "FT_Set_Char_Size(%s,%d,72): %s", font->name, scale, ft_error_string(fterr));
- fterr = FT_Load_Glyph(face, gid, FT_LOAD_IGNORE_TRANSFORM);
- if (fterr)
- {
- fz_warn(ctx, "FT_Load_Glyph(%s,%d,FT_LOAD_IGNORE_TRANSFORM): %s", font->name, gid, ft_error_string(fterr));
- fterr = FT_Load_Glyph(face, gid, FT_LOAD_IGNORE_TRANSFORM | FT_LOAD_NO_HINTING);
- }
- if (fterr)
- {
- fz_warn(ctx, "FT_Load_Glyph(%s,%d,FT_LOAD_IGNORE_TRANSFORM | FT_LOAD_NO_HINTING): %s", font->name, gid, ft_error_string(fterr));
- fz_ft_unlock(ctx);
- return NULL;
- }
- if (font->flags.fake_bold)
- {
- FT_Outline_Embolden(&face->glyph->outline, strength * scale);
- FT_Outline_Translate(&face->glyph->outline, -strength * 0.5f * scale, -strength * 0.5f * scale);
- }
- cc.path = NULL;
- fz_try(ctx)
- {
- cc.ctx = ctx;
- cc.path = fz_new_path(ctx);
- cc.trm = fz_concat(fz_scale(recip, recip), trm);
- fz_moveto(ctx, cc.path, cc.trm.e, cc.trm.f);
- FT_Outline_Decompose(&face->glyph->outline, &outline_funcs, &cc);
- fz_closepath(ctx, cc.path);
- }
- fz_always(ctx)
- {
- fz_ft_unlock(ctx);
- }
- fz_catch(ctx)
- {
- fz_warn(ctx, "freetype cannot decompose outline");
- fz_drop_path(ctx, cc.path);
- return NULL;
- }
- return cc.path;
- }
- /*
- Type 3 fonts...
- */
- fz_font *
- fz_new_type3_font(fz_context *ctx, const char *name, fz_matrix matrix)
- {
- fz_font *font;
- font = fz_new_font(ctx, name, 1, 256);
- fz_try(ctx)
- {
- font->t3procs = fz_calloc(ctx, 256, sizeof(fz_buffer*));
- font->t3lists = fz_calloc(ctx, 256, sizeof(fz_display_list*));
- font->t3widths = fz_calloc(ctx, 256, sizeof(float));
- font->t3flags = fz_calloc(ctx, 256, sizeof(unsigned short));
- }
- fz_catch(ctx)
- {
- fz_drop_font(ctx, font);
- fz_rethrow(ctx);
- }
- font->t3matrix = matrix;
- return font;
- }
- static void
- fz_bound_t3_glyph(fz_context *ctx, fz_font *font, int gid)
- {
- fz_display_list *list;
- fz_device *dev;
- fz_rect *r = get_gid_bbox(ctx, font, gid);
- list = font->t3lists[gid];
- if (!list)
- {
- *r = fz_empty_rect;
- return;
- }
- dev = fz_new_bbox_device(ctx, r);
- fz_try(ctx)
- {
- fz_run_display_list(ctx, list, dev, font->t3matrix, fz_infinite_rect, NULL);
- fz_close_device(ctx, dev);
- }
- fz_always(ctx)
- {
- fz_drop_device(ctx, dev);
- }
- fz_catch(ctx)
- {
- fz_rethrow(ctx);
- }
- /* Update font bbox with glyph's computed bbox if the font bbox is invalid */
- if (font->flags.invalid_bbox)
- font->bbox = fz_union_rect(font->bbox, *r);
- }
- void
- fz_prepare_t3_glyph(fz_context *ctx, fz_font *font, int gid)
- {
- fz_device *dev;
- fz_rect d1_rect;
- /* We've not already loaded this one! */
- assert(font->t3lists[gid] == NULL);
- font->t3lists[gid] = fz_new_display_list(ctx, font->bbox);
- dev = fz_new_list_device(ctx, font->t3lists[gid]);
- dev->flags = FZ_DEVFLAG_FILLCOLOR_UNDEFINED |
- FZ_DEVFLAG_STROKECOLOR_UNDEFINED |
- FZ_DEVFLAG_STARTCAP_UNDEFINED |
- FZ_DEVFLAG_DASHCAP_UNDEFINED |
- FZ_DEVFLAG_ENDCAP_UNDEFINED |
- FZ_DEVFLAG_LINEJOIN_UNDEFINED |
- FZ_DEVFLAG_MITERLIMIT_UNDEFINED |
- FZ_DEVFLAG_LINEWIDTH_UNDEFINED |
- FZ_DEVFLAG_DASH_PATTERN_UNDEFINED;
- fz_try(ctx)
- {
- font->t3run(ctx, font->t3doc, font->t3resources, font->t3procs[gid], dev, fz_identity, NULL, NULL, NULL, NULL);
- fz_close_device(ctx, dev);
- font->t3flags[gid] = dev->flags;
- d1_rect = dev->d1_rect;
- }
- fz_always(ctx)
- {
- fz_drop_device(ctx, dev);
- }
- fz_catch(ctx)
- fz_rethrow(ctx);
- if (fz_display_list_is_empty(ctx, font->t3lists[gid]))
- {
- fz_rect *r = get_gid_bbox(ctx, font, gid);
- /* If empty, no need for a huge bbox, especially as the logic
- * in the 'else if' can make it huge. */
- r->x0 = font->flags.invalid_bbox ? 0 : font->bbox.x0;
- r->y0 = font->flags.invalid_bbox ? 0 : font->bbox.y0;
- r->x1 = r->x0 + .00001f;
- r->y1 = r->y0 + .00001f;
- }
- else if (font->t3flags[gid] & FZ_DEVFLAG_BBOX_DEFINED)
- {
- fz_rect *r = get_gid_bbox(ctx, font, gid);
- *r = fz_transform_rect(d1_rect, font->t3matrix);
- if (font->flags.invalid_bbox || !fz_contains_rect(font->bbox, d1_rect))
- {
- /* Either the font bbox is invalid, or the d1_rect returned is
- * incompatible with it. Either way, don't trust the d1 rect
- * and calculate it from the contents. */
- fz_bound_t3_glyph(ctx, font, gid);
- }
- }
- else
- {
- /* No bbox has been defined for this glyph, so compute it. */
- fz_bound_t3_glyph(ctx, font, gid);
- }
- }
- void
- fz_run_t3_glyph(fz_context *ctx, fz_font *font, int gid, fz_matrix trm, fz_device *dev)
- {
- fz_display_list *list;
- fz_matrix ctm;
- list = font->t3lists[gid];
- if (!list)
- return;
- ctm = fz_concat(font->t3matrix, trm);
- fz_run_display_list(ctx, list, dev, ctm, fz_infinite_rect, NULL);
- }
- fz_pixmap *
- fz_render_t3_glyph_pixmap(fz_context *ctx, fz_font *font, int gid, fz_matrix trm, fz_colorspace *model, const fz_irect *scissor, int aa)
- {
- fz_display_list *list;
- fz_rect bounds;
- fz_irect bbox;
- fz_device *dev = NULL;
- fz_pixmap *glyph;
- fz_pixmap *result = NULL;
- if (gid < 0 || gid > 255)
- return NULL;
- list = font->t3lists[gid];
- if (!list)
- return NULL;
- if (font->t3flags[gid] & FZ_DEVFLAG_MASK)
- {
- if (font->t3flags[gid] & FZ_DEVFLAG_COLOR)
- fz_warn(ctx, "type3 glyph claims to be both masked and colored");
- model = NULL;
- }
- else if (font->t3flags[gid] & FZ_DEVFLAG_COLOR)
- {
- if (!model)
- fz_warn(ctx, "colored type3 glyph wanted in masked context");
- }
- else
- {
- fz_warn(ctx, "type3 glyph doesn't specify masked or colored");
- model = NULL; /* Treat as masked */
- }
- bounds = fz_expand_rect(fz_bound_glyph(ctx, font, gid, trm), 1);
- bbox = fz_irect_from_rect(bounds);
- bbox = fz_intersect_irect(bbox, *scissor);
- /* Glyphs must always have alpha */
- glyph = fz_new_pixmap_with_bbox(ctx, model, bbox, NULL/* FIXME */, 1);
- fz_var(dev);
- fz_try(ctx)
- {
- fz_clear_pixmap(ctx, glyph);
- dev = fz_new_draw_device_type3(ctx, fz_identity, glyph);
- fz_run_t3_glyph(ctx, font, gid, trm, dev);
- fz_close_device(ctx, dev);
- }
- fz_always(ctx)
- {
- fz_drop_device(ctx, dev);
- }
- fz_catch(ctx)
- {
- fz_drop_pixmap(ctx, glyph);
- fz_rethrow(ctx);
- }
- if (!model)
- {
- fz_try(ctx)
- {
- result = fz_alpha_from_gray(ctx, glyph);
- }
- fz_always(ctx)
- {
- fz_drop_pixmap(ctx, glyph);
- }
- fz_catch(ctx)
- {
- fz_rethrow(ctx);
- }
- }
- else
- result = glyph;
- return result;
- }
- fz_glyph *
- fz_render_t3_glyph(fz_context *ctx, fz_font *font, int gid, fz_matrix trm, fz_colorspace *model, const fz_irect *scissor, int aa)
- {
- fz_pixmap *pixmap = fz_render_t3_glyph_pixmap(ctx, font, gid, trm, model, scissor, aa);
- return fz_new_glyph_from_pixmap(ctx, pixmap);
- }
- void
- fz_render_t3_glyph_direct(fz_context *ctx, fz_device *dev, fz_font *font, int gid, fz_matrix trm, void *gstate, fz_default_colorspaces *def_cs, void *fill_gstate, void *stroke_gstate)
- {
- fz_matrix ctm;
- if (gid < 0 || gid > 255)
- return;
- if (font->t3flags[gid] & FZ_DEVFLAG_MASK)
- {
- if (font->t3flags[gid] & FZ_DEVFLAG_COLOR)
- fz_warn(ctx, "type3 glyph claims to be both masked and colored");
- }
- else if (!(font->t3flags[gid] & FZ_DEVFLAG_COLOR))
- {
- fz_warn(ctx, "type3 glyph doesn't specify masked or colored");
- }
- ctm = fz_concat(font->t3matrix, trm);
- font->t3run(ctx, font->t3doc, font->t3resources, font->t3procs[gid], dev, ctm, gstate, def_cs, fill_gstate, stroke_gstate);
- }
- fz_rect
- fz_bound_glyph(fz_context *ctx, fz_font *font, int gid, fz_matrix trm)
- {
- fz_rect rect;
- fz_rect *r = get_gid_bbox(ctx, font, gid);
- if (r)
- {
- /* If the bbox is infinite or empty, distrust it */
- if (fz_is_infinite_rect(*r) || fz_is_empty_rect(*r))
- {
- /* Get the real size from the glyph */
- if (font->ft_face)
- fz_bound_ft_glyph(ctx, font, gid);
- else if (font->t3lists)
- fz_bound_t3_glyph(ctx, font, gid);
- else
- /* If we can't get a real size, fall back to the font
- * bbox. */
- *r = font->bbox;
- /* If the real size came back as empty, then store it as
- * a very small rectangle to avoid us calling this same
- * check every time. */
- if (fz_is_empty_rect(*r))
- {
- r->x0 = 0;
- r->y0 = 0;
- r->x1 = 0.0000001f;
- r->y1 = 0.0000001f;
- }
- }
- rect = *r;
- }
- else
- {
- /* fall back to font bbox */
- rect = font->bbox;
- }
- return fz_transform_rect(rect, trm);
- }
- fz_path *
- fz_outline_glyph(fz_context *ctx, fz_font *font, int gid, fz_matrix ctm)
- {
- if (!font->ft_face)
- return NULL;
- return fz_outline_ft_glyph(ctx, font, gid, ctm);
- }
- int fz_glyph_cacheable(fz_context *ctx, fz_font *font, int gid)
- {
- if (!font->t3procs || !font->t3flags || gid < 0 || gid >= font->glyph_count)
- return 1;
- return (font->t3flags[gid] & FZ_DEVFLAG_UNCACHEABLE) == 0;
- }
- static float
- fz_advance_ft_glyph_aux(fz_context *ctx, fz_font *font, int gid, int wmode, int locked)
- {
- FT_Error fterr;
- FT_Fixed adv = 0;
- int mask;
- /* PDF and substitute font widths. */
- if (font->flags.ft_stretch)
- {
- if (font->width_table)
- {
- if (gid < font->width_count)
- return font->width_table[gid] / 1000.0f;
- return font->width_default / 1000.0f;
- }
- }
- mask = FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING | FT_LOAD_IGNORE_TRANSFORM;
- if (wmode)
- mask |= FT_LOAD_VERTICAL_LAYOUT;
- if (!locked)
- fz_ft_lock(ctx);
- fterr = FT_Get_Advance(font->ft_face, gid, mask, &adv);
- if (!locked)
- fz_ft_unlock(ctx);
- if (fterr && fterr != FT_Err_Invalid_Argument)
- {
- fz_warn(ctx, "FT_Get_Advance(%s,%d): %s", font->name, gid, ft_error_string(fterr));
- if (font->width_table)
- {
- if (gid < font->width_count)
- return font->width_table[gid] / 1000.0f;
- return font->width_default / 1000.0f;
- }
- }
- return (float) adv / ((FT_Face)font->ft_face)->units_per_EM;
- }
- static float
- fz_advance_ft_glyph(fz_context *ctx, fz_font *font, int gid, int wmode)
- {
- return fz_advance_ft_glyph_aux(ctx, font, gid, wmode, 0);
- }
- static float
- fz_advance_t3_glyph(fz_context *ctx, fz_font *font, int gid)
- {
- if (gid < 0 || gid > 255)
- return 0;
- return font->t3widths[gid];
- }
- void
- fz_get_glyph_name(fz_context *ctx, fz_font *font, int glyph, char *buf, int size)
- {
- FT_Face face = font->ft_face;
- if (face)
- {
- if (FT_HAS_GLYPH_NAMES(face))
- {
- int fterr;
- fz_ft_lock(ctx);
- fterr = FT_Get_Glyph_Name(face, glyph, buf, size);
- fz_ft_unlock(ctx);
- if (fterr)
- fz_warn(ctx, "FT_Get_Glyph_Name(%s,%d): %s", font->name, glyph, ft_error_string(fterr));
- }
- else
- fz_snprintf(buf, size, "%d", glyph);
- }
- else
- {
- fz_snprintf(buf, size, "%d", glyph);
- }
- }
- float
- fz_advance_glyph(fz_context *ctx, fz_font *font, int gid, int wmode)
- {
- if (font->ft_face)
- {
- if (wmode)
- return fz_advance_ft_glyph(ctx, font, gid, 1);
- if (gid >= 0 && gid < font->glyph_count)
- {
- float f;
- int block = gid>>8;
- fz_ft_lock(ctx);
- if (!font->advance_cache)
- {
- int n = (font->glyph_count+255)/256;
- fz_try(ctx)
- font->advance_cache = Memento_label(fz_malloc_array(ctx, n, float *), "font_advance_cache");
- fz_catch(ctx)
- {
- fz_ft_unlock(ctx);
- fz_rethrow(ctx);
- }
- memset(font->advance_cache, 0, n * sizeof(float *));
- }
- if (!font->advance_cache[block])
- {
- int i, n;
- fz_try(ctx)
- font->advance_cache[block] = Memento_label(fz_malloc_array(ctx, 256, float), "font_advance_cache");
- fz_catch(ctx)
- {
- fz_ft_unlock(ctx);
- fz_rethrow(ctx);
- }
- n = (block<<8)+256;
- if (n > font->glyph_count)
- n = font->glyph_count;
- n -= (block<<8);
- for (i = 0; i < n; ++i)
- font->advance_cache[block][i] = fz_advance_ft_glyph_aux(ctx, font, (block<<8)+i, 0, 1);
- }
- f = font->advance_cache[block][gid & 255];
- fz_ft_unlock(ctx);
- return f;
- }
- return fz_advance_ft_glyph(ctx, font, gid, 0);
- }
- if (font->t3procs)
- return fz_advance_t3_glyph(ctx, font, gid);
- return 0;
- }
- int
- fz_encode_character(fz_context *ctx, fz_font *font, int ucs)
- {
- if (font->ft_face)
- {
- int idx;
- if (ucs >= 0 && ucs < 0x10000)
- {
- int pg = ucs >> 8;
- int ix = ucs & 0xFF;
- if (!font->encoding_cache[pg])
- {
- int i;
- font->encoding_cache[pg] = fz_malloc_array(ctx, 256, uint16_t);
- fz_ft_lock(ctx);
- for (i = 0; i < 256; ++i)
- font->encoding_cache[pg][i] = FT_Get_Char_Index(font->ft_face, (pg << 8) + i);
- fz_ft_unlock(ctx);
- }
- return font->encoding_cache[pg][ix];
- }
- fz_ft_lock(ctx);
- idx = FT_Get_Char_Index(font->ft_face, ucs);
- fz_ft_unlock(ctx);
- return idx;
- }
- return ucs;
- }
- int
- fz_encode_character_sc(fz_context *ctx, fz_font *font, int unicode)
- {
- if (font->ft_face)
- {
- int cat = ucdn_get_general_category(unicode);
- if (cat == UCDN_GENERAL_CATEGORY_LL || cat == UCDN_GENERAL_CATEGORY_LT)
- {
- int glyph;
- const char *name;
- char buf[20];
- name = fz_glyph_name_from_unicode_sc(unicode);
- if (name)
- {
- fz_ft_lock(ctx);
- glyph = FT_Get_Name_Index(font->ft_face, (char*)name);
- fz_ft_unlock(ctx);
- if (glyph > 0)
- return glyph;
- }
- sprintf(buf, "uni%04X.sc", unicode);
- fz_ft_lock(ctx);
- glyph = FT_Get_Name_Index(font->ft_face, buf);
- fz_ft_unlock(ctx);
- if (glyph > 0)
- return glyph;
- }
- }
- return fz_encode_character(ctx, font, unicode);
- }
- int
- fz_encode_character_by_glyph_name(fz_context *ctx, fz_font *font, const char *glyphname)
- {
- int glyph = 0;
- if (font->ft_face)
- {
- fz_ft_lock(ctx);
- glyph = ft_name_index(font->ft_face, glyphname);
- if (glyph == 0)
- glyph = ft_char_index(font->ft_face, fz_unicode_from_glyph_name(glyphname));
- fz_ft_unlock(ctx);
- }
- // TODO: type3 fonts (not needed for now)
- return glyph;
- }
- /* FIXME: This should take language too eventually, to allow for fonts where we can select different
- * languages using opentype features. */
- int
- fz_encode_character_with_fallback(fz_context *ctx, fz_font *user_font, int unicode, int script, int language, fz_font **out_font)
- {
- fz_font *font;
- int is_serif = user_font->flags.is_serif;
- int is_italic = user_font->flags.is_italic | user_font->flags.fake_italic;
- int is_bold = user_font->flags.is_bold | user_font->flags.fake_bold;
- int gid;
- gid = fz_encode_character(ctx, user_font, unicode);
- if (gid > 0)
- return *out_font = user_font, gid;
- if (script == 0)
- script = ucdn_get_script(unicode);
- /* Fix for ideographic/halfwidth/fullwidth punctuation forms. */
- if ((unicode >= 0x3000 && unicode <= 0x303F) || (unicode >= 0xFF00 && unicode <= 0xFFEF))
- {
- if (script != UCDN_SCRIPT_HANGUL &&
- script != UCDN_SCRIPT_HIRAGANA &&
- script != UCDN_SCRIPT_KATAKANA &&
- script != UCDN_SCRIPT_BOPOMOFO)
- script = UCDN_SCRIPT_HAN;
- }
- font = fz_load_fallback_font(ctx, script, language, is_serif, is_bold, is_italic);
- if (font)
- {
- gid = fz_encode_character(ctx, font, unicode);
- if (gid > 0)
- return *out_font = font, gid;
- }
- #ifndef TOFU_CJK_LANG
- if (script == UCDN_SCRIPT_HAN)
- {
- font = fz_load_fallback_font(ctx, script, FZ_LANG_zh_Hant, is_serif, is_bold, is_italic);
- if (font)
- {
- gid = fz_encode_character(ctx, font, unicode);
- if (gid > 0)
- return *out_font = font, gid;
- }
- font = fz_load_fallback_font(ctx, script, FZ_LANG_ja, is_serif, is_bold, is_italic);
- if (font)
- {
- gid = fz_encode_character(ctx, font, unicode);
- if (gid > 0)
- return *out_font = font, gid;
- }
- font = fz_load_fallback_font(ctx, script, FZ_LANG_ko, is_serif, is_bold, is_italic);
- if (font)
- {
- gid = fz_encode_character(ctx, font, unicode);
- if (gid > 0)
- return *out_font = font, gid;
- }
- font = fz_load_fallback_font(ctx, script, FZ_LANG_zh_Hans, is_serif, is_bold, is_italic);
- if (font)
- {
- gid = fz_encode_character(ctx, font, unicode);
- if (gid > 0)
- return *out_font = font, gid;
- }
- }
- #endif
- font = fz_load_fallback_math_font(ctx);
- if (font)
- {
- gid = fz_encode_character(ctx, font, unicode);
- if (gid > 0)
- return *out_font = font, gid;
- }
- font = fz_load_fallback_music_font(ctx);
- if (font)
- {
- gid = fz_encode_character(ctx, font, unicode);
- if (gid > 0)
- return *out_font = font, gid;
- }
- font = fz_load_fallback_symbol1_font(ctx);
- if (font)
- {
- gid = fz_encode_character(ctx, font, unicode);
- if (gid > 0)
- return *out_font = font, gid;
- }
- font = fz_load_fallback_symbol2_font(ctx);
- if (font)
- {
- gid = fz_encode_character(ctx, font, unicode);
- if (gid > 0)
- return *out_font = font, gid;
- }
- font = fz_load_fallback_emoji_font(ctx);
- if (font)
- {
- gid = fz_encode_character(ctx, font, unicode);
- if (gid > 0)
- return *out_font = font, gid;
- }
- font = fz_load_fallback_boxes_font(ctx);
- if (font)
- {
- gid = fz_encode_character(ctx, font, unicode);
- if (gid > 0)
- return *out_font = font, gid;
- }
- font = fz_new_base14_font(ctx, "Symbol");
- if (font)
- {
- fz_drop_font(ctx, font); /* it's cached in the font context, return a borrowed pointer */
- gid = fz_encode_character(ctx, font, unicode);
- if (gid > 0)
- return *out_font = font, gid;
- }
- return *out_font = user_font, 0;
- }
- int fz_font_is_bold(fz_context *ctx, fz_font *font)
- {
- return font ? font->flags.is_bold : 0;
- }
- int fz_font_is_italic(fz_context *ctx, fz_font *font)
- {
- return font ? font->flags.is_italic : 0;
- }
- int fz_font_is_serif(fz_context *ctx, fz_font *font)
- {
- return font ? font->flags.is_serif : 0;
- }
- int fz_font_is_monospaced(fz_context *ctx, fz_font *font)
- {
- return font ? font->flags.is_mono : 0;
- }
- const char *fz_font_name(fz_context *ctx, fz_font *font)
- {
- return font ? font->name : "";
- }
- fz_buffer **fz_font_t3_procs(fz_context *ctx, fz_font *font)
- {
- return font ? font->t3procs : NULL;
- }
- fz_rect fz_font_bbox(fz_context *ctx, fz_font *font)
- {
- return font->bbox;
- }
- void *fz_font_ft_face(fz_context *ctx, fz_font *font)
- {
- return font ? font->ft_face : NULL;
- }
- fz_font_flags_t *fz_font_flags(fz_font *font)
- {
- return font ? &font->flags : NULL;
- }
- fz_shaper_data_t *fz_font_shaper_data(fz_context *ctx, fz_font *font)
- {
- return font ? &font->shaper_data : NULL;
- }
- void fz_font_digest(fz_context *ctx, fz_font *font, unsigned char digest[16])
- {
- if (!font->buffer)
- fz_throw(ctx, FZ_ERROR_ARGUMENT, "no font file for digest");
- if (!font->has_digest)
- {
- fz_md5_buffer(ctx, font->buffer, font->digest);
- font->has_digest = 1;
- }
- memcpy(digest, font->digest, 16);
- }
- #define CHR(a,b,c,d) ((a<<24) | (b<<16) | (c<<8) | d)
- typedef struct
- {
- uint32_t offset;
- uint32_t length;
- } ttc_block_details_t;
- /* The operation of the following is largely based on the operation of
- * https://github.com/fontist/extract_ttc/blob/main/ext/stripttc/stripttc.c
- * released under a BSD 3-clause license.
- */
- fz_buffer *
- fz_extract_ttf_from_ttc(fz_context *ctx, fz_font *font)
- {
- fz_stream *stream;
- uint32_t tmp;
- int i, count;
- fz_buffer *buf = NULL;
- fz_output *out = NULL;
- ttc_block_details_t *bd = NULL;
- uint32_t start_pos;
- uint32_t csumpos = 0;
- if (!font || !font->buffer)
- fz_throw(ctx, FZ_ERROR_ARGUMENT, "missing input");
- stream = fz_open_buffer(ctx, font->buffer);
- fz_var(buf);
- fz_var(out);
- fz_var(bd);
- fz_try(ctx)
- {
- /* Signature */
- if (fz_read_uint32(ctx, stream) != CHR('t','t','c','f'))
- fz_throw(ctx, FZ_ERROR_FORMAT, "Not a ttc");
- /* Version */
- tmp = fz_read_uint32(ctx, stream);
- if (tmp != 0x10000 && tmp != 0x20000)
- fz_throw(ctx, FZ_ERROR_FORMAT, "Unsupported TTC version");
- /* How many subfonts are there? */
- tmp = fz_read_uint32(ctx, stream);
- if ((uint32_t)font->subfont >= tmp || font->subfont < 0)
- fz_throw(ctx, FZ_ERROR_FORMAT, "Bad subfont in TTC");
- /* Read through the index table until we get the one for our subfont. */
- for (i = 0; i <= font->subfont; i++)
- tmp = fz_read_uint32(ctx, stream);
- fz_seek(ctx, stream, tmp, SEEK_SET);
- buf = fz_new_buffer(ctx, 1);
- out = fz_new_output_with_buffer(ctx, buf);
- fz_write_uint32_be(ctx, out, fz_read_uint32(ctx, stream)); /* sfnt version */
- fz_write_uint16_be(ctx, out, count = fz_read_uint16(ctx, stream)); /* table count */
- fz_write_uint16_be(ctx, out, fz_read_uint16(ctx, stream)); /* bsearch header */
- fz_write_uint16_be(ctx, out, fz_read_uint16(ctx, stream));
- fz_write_uint16_be(ctx, out, fz_read_uint16(ctx, stream));
- /* We are currently here... */
- start_pos = 4+2+2+2+2;
- /* And after we've written the header, we will be here. */
- start_pos += count*4*4;
- bd = fz_malloc_array(ctx, count, ttc_block_details_t);
- for (i = 0; i < count; i++)
- {
- uint32_t tag;
- fz_write_uint32_be(ctx, out, tag = fz_read_uint32(ctx, stream));
- fz_write_uint32_be(ctx, out, fz_read_uint32(ctx, stream)); /* checksum */
- bd[i].offset = fz_read_uint32(ctx, stream);
- fz_write_uint32_be(ctx, out, start_pos);
- if (tag == CHR('h','e','a','d'))
- csumpos = start_pos + 8;
- fz_write_uint32_be(ctx, out, bd[i].length = fz_read_uint32(ctx, stream));
- start_pos += (bd[i].length + 3) & ~3;
- }
- for (i = 0; i < count; i++)
- {
- uint32_t j;
- fz_seek(ctx, stream, bd[i].offset, SEEK_SET);
- for (j = 0; j < bd[i].length; j++)
- fz_write_byte(ctx, out, fz_read_byte(ctx, stream));
- if (bd[i].length & 1)
- {
- fz_write_byte(ctx, out, 0);
- bd[i].length++;
- }
- if (bd[i].length & 2)
- fz_write_uint16_be(ctx, out, 0);
- }
- fz_close_output(ctx, out);
- }
- fz_always(ctx)
- {
- fz_free(ctx, bd);
- fz_drop_output(ctx, out);
- fz_drop_stream(ctx, stream);
- }
- fz_catch(ctx)
- {
- fz_drop_buffer(ctx, buf);
- fz_rethrow(ctx);
- }
- /* Now fixup the checksum */
- if (csumpos)
- {
- unsigned char *data;
- uint32_t sum = 0;
- uint32_t j;
- size_t len = fz_buffer_storage(ctx, buf, &data);
- /* First off, blat the old checksum */
- memset(data+csumpos, 0, 4);
- /* Calculate the new sum. */
- for (j = 0; j < len; j += 4)
- {
- uint32_t v = (data[j]<<24) | (data[j+1]<<16) | (data[j+2]<<8) | (data[j+3]);
- sum += v;
- }
- sum = 0xb1b0afba-sum;
- /* Insert it. */
- data[csumpos] = sum>>24;
- data[csumpos+1] = sum>>16;
- data[csumpos+2] = sum>>8;
- data[csumpos+3] = sum;
- }
- return buf;
- }
- void fz_enumerate_font_cmap(fz_context *ctx, fz_font *font, fz_cmap_callback *cb, void *opaque)
- {
- unsigned long ucs;
- unsigned int gid;
- if (font == NULL || font->ft_face == NULL)
- return;
- fz_ft_lock(ctx);
- for (ucs = FT_Get_First_Char(font->ft_face, &gid); gid > 0; ucs = FT_Get_Next_Char(font->ft_face, ucs, &gid))
- {
- fz_ft_unlock(ctx);
- cb(ctx, opaque, ucs, gid);
- fz_ft_lock(ctx);
- }
- fz_ft_unlock(ctx);
- }
- void fz_calculate_font_ascender_descender(fz_context *ctx, fz_font *font)
- {
- int i, n;
- fz_rect bounds = fz_empty_rect;
- fz_matrix trm = { 1, 0, 0, 1, 0, 0 };
- if (font == NULL)
- return;
- if (font->ascdesc_src == FZ_ASCDESC_FROM_BOUNDS)
- return;
- n = font->glyph_count;
- for (i = 0; i < n; i++)
- {
- bounds = fz_union_rect(bounds, fz_bound_glyph(ctx, font, i, trm));
- }
- if (bounds.y1 > font->ascender)
- font->ascender = bounds.y1;
- if (bounds.y0 < font->descender)
- font->descender = bounds.y0;
- font->ascdesc_src = FZ_ASCDESC_FROM_BOUNDS;
- }
|